from uuid import uuid4
from types import GetSetDescriptorType

import requests
from django.shortcuts import render
from django.contrib.auth.models import User, Group
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
from django.contrib.auth.views import LoginView
from ability.models import UserProfile
from rest_framework import viewsets, mixins, request, permissions, status, pagination
from rest_framework.views import APIView
from rest_framework.generics import ListAPIView
from rest_framework.renderers import JSONRenderer
from ability.serializer.serializers import *
from ability.cloud import *
import ability.permissions as pm
from ability.enums import trans
import uuid
from django.conf import settings
from django.db.models import Q, Sum, Count
from datetime import datetime, timedelta
from rest_framework.parsers import FormParser, MultiPartParser
import xlrd
from rest_framework import exceptions
from rest_framework.views import exception_handler
from django.contrib.auth import backends, get_user_model
import logging
logger = logging.getLogger(__name__)
import traceback
from django.http import JsonResponse
import random
import ability.timeutil as timeutil
from django.http import HttpResponseRedirect, HttpResponse,FileResponse
# from starlette.responses import FileResponse
import json
from ability.validators import *
from django.db import transaction
import ability.cas as cas
import ability.sso as sso
import time
from webevent.read import readReportLogs
from zipfile import ZipFile
from webevent.serializers import WebEventSerializer
from ability.excepts import LogicException
from ..eanxing import study_record_data_send, virtual_data_send
from ..models import VncServer,Experiment,Report,StudentExperiment,Image
from study.utils import run_onvnc, port_occupancy_check, kill_process_by_port, test_internet_speed
import study.proxmox_utils as proxmox
import time
import urllib.request
from django.core.cache import caches

class EmberJSONRenderer(JSONRenderer):

    def render(self, data, accepted_media_type=None, renderer_context=None):
        data = {'element': data}
        return super(EmberJSONRenderer, self).render(data, accepted_media_type, renderer_context)

class UserViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = UserProfile.objects.all().order_by('-date_joined')
    serializer_class = UserListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

class UserProfileViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = UserProfileSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission|pm.StudentPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(UserProfileViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return UserProfile.objects.filter(user__id = self.kwargs['pk'])

    def retrieve(self, request, userid=None):
        try:
            one = self.request.user
            serializer = UserProfileSerializer(one)
            self.response_format["data"] = serializer.data
        except Teacher.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '用户ID不存在'
        
        return Response(self.response_format)

# 教师管理相关视图

class TeacherListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Teacher.objects.all().order_by('-user__create_time')
    serializer_class = TeacherListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def get_queryset(self):
        queryset = Teacher.objects.all().order_by('-user__create_time')
        userid = self.request.query_params.get('userid', None)
        username = self.request.query_params.get('username', None)
        school_id = self.request.query_params.get('school_id', None)
        college_id = self.request.query_params.get('college_id', None)
        identity = self.request.query_params.get('identity', None)
        status = self.request.query_params.get('status', None)
        keyword = self.request.query_params.get('keyword', None)
        banned = [None,'']
        if userid not in banned:
            queryset = queryset.filter(user__id=userid)
        if username not in banned:
            # queryset = queryset.filter(user__real_name=username)
            queryset = queryset.filter(user__real_name__icontains=username)
        if school_id not in banned:
            queryset = queryset.filter(college__school__id=school_id)
        if college_id not in banned:
            queryset = queryset.filter(college__id=college_id)
        if identity not in banned:
            queryset = queryset.filter(teacher_type=trans.teacher_identity[identity])
        if status not in banned:
            queryset = queryset.filter(user__user_status=trans.status[status])
        if keyword not in banned:
            if keyword.isnumeric():
                queryset = queryset.filter(Q(user__id=keyword)|Q(teacherID=keyword))
            else:
                queryset = queryset.filter(Q(user__real_name__icontains=keyword))
        
        return queryset


class TeacherOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = TeacherSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(TeacherOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Teacher.objects.filter(user__id = self.kwargs['pk'])

    def retrieve(self, request, userid=None):
        queryset = Teacher.objects.all()
        try:
            one = queryset.get(user__id = self.kwargs['userid'])
            serializer = TeacherSerializer(one)
            self.response_format["data"] = serializer.data
        except Teacher.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '用户ID不存在'
        
        return Response(self.response_format)
    
    """
    def create(self, request, *args, **kwargs):
        print(self.request.data['username'])
        super().create(**kwargs)
    """
class TeacherCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = TeacherCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(TeacherCreateViewSet, self).__init__(**kwargs)
    def perform_create(self, serializer):
        # 登录账户和教师为一对一关系，创建教师同时需要创建相应的登录账户，默认密码可在settings中配置，需要用户手动修改重置
        with transaction.atomic():
            user_create = UserProfile()
            user_create.set_password(str(self.request.data['phone']))
            user_create.phone = GetPostParaOrNone(self.request.data, 'phone', default='')
            user_create.email = GetPostParaOrNone(self.request.data, 'email', default='')
            user_create.sex = self.request.data['sex']
            user_create.user_status = trans.status[str(self.request.data['status'])]
            user_create.username = self.request.data['phone']
            user_create.user_type = "T"
            user_create.real_name = self.request.data['real_name']
            user_create.save()
            teacher_new = Teacher.addOne(user_create, '', 'C', teacherID='')
    def create(self, request, *args, **kwargs):
        try:
            phone = request.data['phone']
            if UserProfile.phone_exists(phone) or UserProfile.username_exists(phone):
                raise LogicException('该手机号用户已存在')
            super(TeacherCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "教师创建成功"
            return Response(self.response_format)
        except LogicException as err:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(err)
            return Response(self.response_format)
        except Exception as err:
            traceback.print_exc()
            logger.error(err)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(err)
            return Response(self.response_format)

class TeacherUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = TeacherUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    lookup_field = "user__id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(TeacherUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return Teacher.objects.filter(user__id = self.kwargs['user__id'])

    def perform_update(self, serializer):
        teacher_modify = serializer.save()

        # user_id = GetPostParaOrNone(self.request.data,"user_id")
        real_name = GetPostParaOrNone(self.request.data,"real_name")
        phone = GetPostParaOrNone(self.request.data,"phone")
        email = GetPostParaOrNone(self.request.data,"email")
        # college_id = GetPostParaOrNone(self.request.data,"college_id")
        status = GetPostParaOrNone(self.request.data,"status")
        sex = GetPostParaOrNone(self.request.data,"sex")
        # identity = GetPostParaOrNone(self.request.data,"identity")

        user_modify = teacher_modify.user
        if real_name is not None:
            user_modify.real_name = real_name
        if phone is not None and phone != user_modify.phone:
            if UserProfile.phone_exists(phone) or UserProfile.username_exists(phone):
                raise LogicException('该手机号用户已存在')
            user_modify.phone = phone
            user_modify.username = phone
        if email is not None:
            user_modify.email = email
        if status is not None:
            user_modify.user_status = trans.status[str(status)]
        if sex is not None:
            user_modify.sex = str(sex)

        teacher_modify.save()
        user_modify.save()
        """
        teacher_modify = serializer.save()
        teacher_modify.college_id = 
        user_modify = 
        serializer.save()
        """
    def update(self, request, *args, **kwargs):
        try:
            super(TeacherUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "教师更新成功"
        except LogicException as err:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(err)
            return Response(self.response_format)
        except Exception as err:
            logger.error(err)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(err)
        return Response(self.response_format)
class TeacherBlockView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(TeacherBlockView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        """ try:
            return Teacher.objects.get(id=obj_id)
        except (Teacher.DoesNotExist, ValidationError):
            raise status.HTTP_400_BAD_REQUEST """
        try:
            return Teacher.objects.get(user__id = obj_id)
        except Teacher.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Teacher.objects.get(user__id = id)
            """ try:
                DemoConfig.objects.get(id=id)
            except (DemoConfig.DoesNotExist, ValidationError):
                raise status.HTTP_400_BAD_REQUEST """
        return True

    def post(self, request, *args, **kwargs):
        try:
            id_list = request.data['users']
        except:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "users参数错误"
            return Response(self.response_format)
        instances = []
        try:
            status = trans.status[str(request.data['status'])]
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "status参数错误"
            return Response(self.response_format)
        for id in id_list:
            obj = self.get_object(obj_id=id)
            if obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '用户ID:'+str(id)+'不存在\n'
                continue
            obj1 = obj.user
            obj1.user_status = status
            obj1.save()
            self.message += '用户ID:'+str(id)+'状态修改成功\n'
            instances.append(obj)
        serializer = TeacherBlockSerializer(instances, many=True)
        self.response_format["message"] = self.message
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

# 用户管理相关视图

class StudentListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Student.objects.all().order_by('-user__create_time')
    serializer_class = StudentListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def get_queryset(self):
        queryset = Student.objects.all().order_by('-user__create_time')
        userid = self.request.query_params.get('userid', None)
        username = self.request.query_params.get('username', None)
        school_id = self.request.query_params.get('school_id', None)
        college_id = self.request.query_params.get('college_id', None)
        major_id = self.request.query_params.get('major_id', None)
        class_id = self.request.query_params.get('class_id', None)
        status = self.request.query_params.get('status', None)
        keyword = self.request.query_params.get('keyword', None)
        banned = [None,'']
        if userid not in banned:
            queryset = queryset.filter(user__id=userid)
        if username not in banned:
            # queryset = queryset.filter(user__real_name=username)
            queryset = queryset.filter(user__real_name__icontains=username)
        if school_id not in banned:
            queryset = queryset.filter(belong_class__major__college__school__id=school_id)
        if college_id not in banned:
            queryset = queryset.filter(belong_class__major__college__id=college_id)
        if major_id not in banned:
            queryset = queryset.filter(belong_class__major__id=major_id)
        if class_id not in banned:
            queryset = queryset.filter(belong_class__id=class_id)
        if status not in banned:
            queryset = queryset.filter(user__user_status=trans.status[status])
        if keyword not in banned:
            if keyword.isnumeric():
                queryset = queryset.filter(Q(user__id=keyword)|Q(studentID=keyword))
            else:
                queryset = queryset.filter(Q(user__real_name__icontains=keyword))
        
        return queryset

class StudentOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = StudentSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StudentOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Student.objects.filter(user__id = self.kwargs['pk'])

    def retrieve(self, request, userid=None):
        queryset = Student.objects.all()
        try:
            one = queryset.get(user__id = self.kwargs['userid'])
            serializer = StudentSerializer(one)
            self.response_format["data"] = serializer.data
        except Student.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '用户ID不存在'
        
        return Response(self.response_format)

class StudentCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = StudentCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StudentCreateViewSet, self).__init__(**kwargs)
    def perform_create(self, serializer):
        # 登录账户和教师为一对一关系，创建教师同时需要创建相应的登录账户，默认密码可在settings中配置，需要用户手动修改重置
        user_create = UserProfile()
        user_create.set_password('123456')
        user_create.phone = GetPostParaOrNone(self.request.data, 'phone', default='')
        if UserProfile.objects.filter(phone=user_create.phone,user_type='S').first() not in ['',None]:
            raise LogicException("手机号已存在")
        user_create.email = GetPostParaOrNone(self.request.data, 'email', default='')
        if UserProfile.objects.filter(email=user_create.email,user_type='S').first() not in ['',None]:
            raise LogicException("邮箱已存在")
        # user_create.sex = trans.sex[str(self.request.data['sex'])]
        user_create.sex = str(self.request.data['sex'])
        user_create.user_status = trans.status[str(self.request.data['status'])]
        # user_create.username = self.request.data['user_id']
        user_create.username = self.request.data['username']
        if UserProfile.objects.filter(username=user_create.username,user_type='S').first() not in ['',None]:
            raise LogicException("用户名已存在")
        user_create.user_type = "S"
        user_create.real_name = self.request.data['username']
        admin = UserProfile.objects.filter(phone=user_create.phone, user_type='A').first()
        if UserProfile.objects.filter(phone=user_create.phone,user_type='A').first() not in ['',None]:
            #说明此账号已经是一个管理员
            admin.phone = user_create.phone
            admin.email = user_create.email
            admin.sex = user_create.sex
            admin.user_status = user_create.user_status
            admin.username = user_create.username
            admin.real_name = user_create.real_name
            admin.create_time = datetime.now()
            admin.save()
            student_new = serializer.save()
            student_new.user = admin
            student_new.save()
            return
        user_create.save()
        student_new = serializer.save()
        student_new.user = user_create
        # student_new.belong_class_id = self.request.data['class_id']
        student_new.save()
    def create(self, request, *args, **kwargs):
        try:
            super(StudentCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "用户创建成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class StudentUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = StudentUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    lookup_field = "user__id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StudentUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return Student.objects.filter(user__id = self.kwargs['user__id'])

    def perform_update(self, serializer):
        student_modify = serializer.save()
        userid = GetPostParaOrNone(self.request.data, "userid")
        status = GetPostParaOrNone(self.request.data, "status")
        if status != 1 and str(self.request.user.id) == userid:
            raise LogicException("不可以修改当前登录帐号的状态！！！")
        user_id = GetPostParaOrNone(self.request.data,"user_id")
        username = GetPostParaOrNone(self.request.data,"username")
        if UserProfile.objects.filter(username=username).exclude(id=userid).count() > 0:
            raise LogicException("用户名已存在")
        phone = GetPostParaOrNone(self.request.data,"phone")
        if UserProfile.objects.filter(phone=phone).exclude(id=userid).first() not in ['',None]:
            raise LogicException("手机号已存在")
        email = GetPostParaOrNone(self.request.data,"email")
        if UserProfile.objects.filter(email=email).exclude(id=userid).first() not in ['',None]:
            raise LogicException("邮箱已存在")
        class_id = GetPostParaOrNone(self.request.data,"class_id")
        status = GetPostParaOrNone(self.request.data,"status")
        sex = GetPostParaOrNone(self.request.data,"sex")

        if class_id is not None:
            student_modify.belong_class_id = class_id

        user_modify = student_modify.user

        if username is not None:
            user_modify.real_name = username
        if phone is not None:
            user_modify.phone = phone
        if email is not None:
            user_modify.email = email
        if status is not None:
            user_modify.user_status = trans.status[str(status)]
        if sex is not None:
            # user_modify.sex = trans.sex[str(sex)]
            user_modify.sex = str(sex)
        if user_id is not None:
            user_modify.username = user_id

        student_modify.save()
        user_modify.save()
        """
        teacher_modify = serializer.save()
        teacher_modify.college_id = 
        user_modify = 
        serializer.save()
        """
    def update(self, request, *args, **kwargs):
        try:
            super(StudentUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "用户更新成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)
class StudentBlockView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(StudentBlockView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        """ try:
            return Teacher.objects.get(id=obj_id)
        except (Teacher.DoesNotExist, ValidationError):
            raise status.HTTP_400_BAD_REQUEST """
        try:
            return Student.objects.get(user__id = obj_id)
        except Student.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Student.objects.get(user__id = id)
            """ try:
                DemoConfig.objects.get(id=id)
            except (DemoConfig.DoesNotExist, ValidationError):
                raise status.HTTP_400_BAD_REQUEST """
        return True

    def post(self, request, *args, **kwargs):
        try:
            id_list = request.data['users']
        except:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "users参数错误"
            return Response(self.response_format)
        instances = []
        try:
            status = trans.status[str(request.data['status'])]
            if str(self.request.user.id) in id_list and request.data['status']!=1:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.response_format["message"] = "不可以修改当前登录帐号的状态！！！"
                return Response(self.response_format)
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "status参数错误"
            return Response(self.response_format)
        for id in id_list:
            obj = self.get_object(obj_id=id)
            if obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '用户ID:'+str(id)+'不存在\n'
                continue
            obj1 = obj.user
            obj1.user_status = status
            obj1.save()
            self.message += '用户ID:'+str(id)+'状态修改成功\n'
            instances.append(obj)
        serializer = StudentBlockSerializer(instances, many=True)
        self.response_format["message"] = self.message
        self.response_format["data"] = serializer.data
        return Response(self.response_format)
# 用户管理相关视图

class ExpertListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Expert.objects.all().order_by('-user__create_time')
    serializer_class = ExpertListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def get_queryset(self):
        queryset = Expert.objects.all().order_by('-user__create_time')
        userid = self.request.query_params.get('userid', None)
        username = self.request.query_params.get('username', None)
        school_id = self.request.query_params.get('school_id', None)
        job_title = self.request.query_params.get('job_title', None)
        status = self.request.query_params.get('status', None)
        banned = [None,'']
        if userid not in banned:
            queryset = queryset.filter(user__id=userid)
        if username not in banned:
            queryset = queryset.filter(user__real_name__icontains=username)
        if school_id not in banned:
            queryset = queryset.filter(belong_class__major__college__school__id=school_id)
        if job_title not in banned:
            queryset = queryset.filter(job_title=job_title)
        if status not in banned:
            queryset = queryset.filter(user__user_status=trans.status[status])
        
        return queryset

class ExpertOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = ExpertSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ExpertOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Expert.objects.filter(user__id = self.kwargs['pk'])

    def retrieve(self, request, userid=None):
        queryset = Expert.objects.all()
        try:
            one = queryset.get(user__id = self.kwargs['userid'])
            serializer = ExpertSerializer(one)
            self.response_format["data"] = serializer.data
        except Expert.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '用户ID不存在'
        
        return Response(self.response_format)
    

class ExpertCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = ExpertCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ExpertCreateViewSet, self).__init__(**kwargs)
    def perform_create(self, serializer):
        # 登录账户和教师为一对一关系，创建教师同时需要创建相应的登录账户，默认密码可在settings中配置，需要用户手动修改重置
        user_create = UserProfile()
        user_create.set_password(str(uuid.uuid4()))
        user_create.phone = GetPostParaOrNone(self.request.data, 'phone', default='')
        user_create.email = GetPostParaOrNone(self.request.data, 'email', default='')
        user_create.sex = trans.sex[str(self.request.data['sex'])]
        user_create.status = trans.status[str(self.request.data['status'])]
        user_create.username = self.request.data['user_id']
        user_create.user_type = "E"
        user_create.real_name = self.request.data['username']
        user_create.save()
        expert_new = serializer.save()
        expert_new.user = user_create
        expert_new.school_id = self.request.data['school_id']
        expert_new.save()
    def create(self, request, *args, **kwargs):
        try:
            super(ExpertCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "教授创建成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class ExpertUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = ExpertUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    lookup_field = "user__id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ExpertUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return Expert.objects.filter(user__id = self.kwargs['user__id'])

    def perform_update(self, serializer):
        expert_modify = serializer.save()

        user_id = GetPostParaOrNone(self.request.data,"user_id")
        username = GetPostParaOrNone(self.request.data,"username")
        phone = GetPostParaOrNone(self.request.data,"phone")
        email = GetPostParaOrNone(self.request.data,"email")
        school_id = GetPostParaOrNone(self.request.data,"school_id")
        status = GetPostParaOrNone(self.request.data,"status")
        sex = GetPostParaOrNone(self.request.data,"sex")

        if school_id is not None:
            expert_modify.school_id = school_id

        user_modify = expert_modify.user

        if username is not None:
            user_modify.real_name = username
        if phone is not None:
            user_modify.phone = phone
        if email is not None:
            user_modify.email = email
        if status is not None:
            user_modify.status = trans.status[str(status)]
        if sex is not None:
            user_modify.sex = trans.sex[str(sex)]
        if user_id is not None:
            user_modify.username = user_id

        expert_modify.save()
        user_modify.save()
        """
        teacher_modify = serializer.save()
        teacher_modify.college_id = 
        user_modify = 
        serializer.save()
        """
    def update(self, request, *args, **kwargs):
        try:
            super(ExpertUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "专家更新成功"
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)

class ExpertBlockView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ExpertBlockView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        """ try:
            return Teacher.objects.get(id=obj_id)
        except (Teacher.DoesNotExist, ValidationError):
            raise status.HTTP_400_BAD_REQUEST """
        try:
            return Expert.objects.get(user__id = obj_id)
        except Expert.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Expert.objects.get(user__id = id)
            """ try:
                DemoConfig.objects.get(id=id)
            except (DemoConfig.DoesNotExist, ValidationError):
                raise status.HTTP_400_BAD_REQUEST """
        return True

    def post(self, request, *args, **kwargs):
        id_list = request.data['users']
        instances = []
        try:
            status = trans.status[str(request.data['status'])]
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "status参数错误"
            return Response(self.response_format)
        for id in id_list:
            obj = self.get_object(obj_id=id)
            if obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '用户ID:'+str(id)+'不存在\n'
                continue
            obj1 = obj.user
            obj1.user_status = status
            obj1.save()
            self.message += '用户ID:'+str(id)+'状态修改成功\n'
            instances.append(obj)
        serializer = ExpertBlockSerializer(instances, many=True)
        self.response_format["message"] = self.message
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

class GroupViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
    permission_classes = [pm.CustomIsAuthenticated]

class StudentViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

class KnowledgeViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows groups to be viewed or edited.
    """
    queryset = Knowledge.objects.all()
    serializer_class = KnowledgeSerializer
    permission_classes = [pm.CustomIsAuthenticated]

class FuzzySearchSchoolView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.ExpertPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(FuzzySearchSchoolView, self).__init__(**kwargs)

    def get(self, request, *args, **kwargs):
        keyword = self.request.query_params.get('keyword', '')
        schools_res = School.objects.filter(school_name__icontains=keyword).filter(status='N')[:20]
        serializer = FuzzySearchSchoolSerializer(schools_res, many=True)
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

class FuzzySearchCollegeView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(FuzzySearchCollegeView, self).__init__(**kwargs)

    def get(self, request, *args, **kwargs):
        keyword = self.request.query_params.get('keyword', '')
        school_id = self.request.query_params.get('school_id', None)
        if school_id is not None:
            college_res = College.objects.filter(Q(college_name__icontains=keyword), Q(school__id=school_id)).filter(status='N')[:20]
        else:
            college_res = College.objects.filter(Q(college_name__icontains=keyword)).filter(status='N')[:20]
        serializer = FuzzySearchCollegeSerializer(college_res, many=True)
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

class FuzzySearchMajorView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(FuzzySearchMajorView, self).__init__(**kwargs)

    def get(self, request, *args, **kwargs):
        keyword = self.request.query_params.get('keyword', '')
        college_id = self.request.query_params.get('college_id', None)
        if college_id is not None:
            major_res = Major.objects.filter(Q(major_name__icontains=keyword), Q(college__id=college_id)).filter(status='N')[:20]
        else:
            major_res = Major.objects.filter(Q(major_name__icontains=keyword)).filter(status='N')[:20]
        serializer = FuzzySearchMajorSerializer(major_res, many=True)
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

class FuzzySearchClassView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(FuzzySearchClassView, self).__init__(**kwargs)

    def get(self, request, *args, **kwargs):
        keyword = self.request.query_params.get('keyword', '')
        major_id = self.request.query_params.get('major_id', None)
        if major_id is not None:
            class_res = Class.objects.filter(Q(class_name__icontains=keyword), Q(major__id=major_id)).filter(status='N')[:20]
        else:
            class_res = Class.objects.filter(Q(class_name__icontains=keyword)).filter(status='N')[:20]
        serializer = FuzzySearchClassSerializer(class_res, many=True)
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

class FileUploadView(APIView):
    parser_classes = (FormParser, MultiPartParser)
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(FileUploadView, self).__init__(**kwargs)

    def post(self, request, format=None):
        now = datetime.now()
        timestampStr = now.strftime("%Y_%m_%d_%H_%M_%S_%f")
        up_file = request.FILES['file']
        batch_type = GetPostParaOrNone(self.request.data,"type")
        if batch_type is None:
            self.response_format["error_code"] = ErrorCode.missing_parameter.value
            self.response_format["message"] = '参数type缺失'
            return Response(self.response_format)
        file_to_location = 'BatchImportFiles/' +timestampStr + '_' + up_file.name
        destination = open(file_to_location, 'wb+')
        for chunk in up_file.chunks():
            destination.write(chunk)
        destination.close() 

        success = 0
        error_code = 0
        error_message= []

        try:
            # 针对不同导入类型分别进行处理
            # 班级批量导入
            if str(batch_type) == "1":
                data = xlrd.open_workbook(file_to_location)
                table = data.sheets()[0]
                if table.nrows < 3:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.response_format["message"] = '至少应包含一条数据'
                    return Response(self.response_format)
                for i in range(2, table.nrows):
                    datas = table.row_values(i)
                    class_new = Class()
                    school = School.objects.get_or_create(school_name=datas[2])[0]
                    college = College.objects.filter(school=school).get_or_create(college_name=datas[3])[0]
                    college.school = school
                    college.save()
                    major = Major.objects.filter(college=college).get_or_create(major_name=datas[4])[0]
                    major.college = college
                    major.save()
                    class_find = Class.objects.filter(major=major, class_name=datas[0])
                    if class_find.exists():
                        error_message.append("第"+str(i+1)+"行出现错误：班级已存在")
                        error_code = ErrorCode.parameter_error.value
                        continue
                    class_new.major = major
                    class_new.grade = datas[1]
                    class_new.class_name = datas[0]
                    if datas[5] in trans.class_status_zh.keys():
                        class_new.status = trans.class_status_zh[str(datas[5])]
                        class_new.save()
                        success += 1
                    else:
                        error_message.append("第"+str(i+1)+"行出现错误：班级状态错误")
                        error_code = ErrorCode.parameter_error.value
                        continue
                error_message.append("班级批量导入成功"+ str(success) +"条数据！")
                
            # 班级用户批量导入模板
            elif str(batch_type) == "2":
                data = xlrd.open_workbook(file_to_location)
                table = data.sheets()[0]
                if table.nrows < 3:
                    return Response("至少应包含一行数据！", status.HTTP_200_OK)
                for i in range(2, table.nrows):
                    datas = table.row_values(i)
                    student_find = Student.objects.filter(user__real_name=datas[0], user__id=datas[1])
                    if student_find.exists():
                        school = School.objects.get_or_create(school_name=datas[2])[0]
                        college = College.objects.filter(school=school).get_or_create(college_name=datas[3])[0]
                        college.school = school
                        college.save()
                        major = Major.objects.filter(college=college).get_or_create(major_name=datas[4])[0]
                        major.college = college
                        major.save()
                        belong_class = Class.objects.filter(major=major).get_or_create(class_name=datas[5])[0]
                        belong_class.major = major
                        belong_class.save()
                        student = student_find[0]
                        student.belong_class = belong_class
                        student.save()
                        success += 1
                    else:
                        error_code = ErrorCode.parameter_error.value
                        error_message.append("第"+str(i+1)+"行出现错误：用户不存在")
                        continue
                error_message.append("班级批量导入成功"+ str(success) +"条数据！")
            # 教师批量导入模板
            elif str(batch_type) == "3":
                data = xlrd.open_workbook(file_to_location)
                table = data.sheets()[0]
                if table.nrows < 3:
                    return Response("至少应包含一行数据！", status.HTTP_200_OK)
                for i in range(2, table.nrows):
                    datas = table.row_values(i)
                    if PhoneExists(str(datas[1])):
                        error_code = ErrorCode.parameter_error.value
                        error_message.append("第"+str(i+1)+"行出现错误：手机号已存在！")
                        continue
                    school = School.objects.filter(school_name=datas[5]).first()
                    if school is None:
                        error_message.append("第"+str(i+1)+"行出现错误：学校不存在！")
                        continue
                    college = College.objects.filter(school=school, college_name=datas[6]).first()
                    if college is None:
                        error_message.append("第"+str(i+1)+"行出现错误：学院不存在！")
                        continue
                    with transaction.atomic():
                        user_create = UserProfile()
                        user_create.set_password(settings.USER_DEFAULT_PASSWORD)
                        user_create.phone = str(datas[1])
                        user_create.email = str(datas[9])
                        user_create.sex = trans.sex_zh[str(datas[3])]
                        user_create.status = trans.status_zh[str(datas[8])]
                        user_create.username = str(datas[2])
                        user_create.user_type = "T"
                        user_create.real_name = str(datas[0])
                        user_create.save()
                        teacher_new = Teacher()
                        teacher_new.user = user_create
                        teacher_new.college = college
                        teacher_new.teacherID = str(datas[4])
                        teacher_new.teacher_type = trans.teacher_identity_zh[str(datas[7])]
                        teacher_new.save()
                        success += 1
                error_message.append("教师批量导入成功"+ str(success) +"条数据！")
            
            # 用户批量导入模板
            elif str(batch_type) == "4":
                data = xlrd.open_workbook(file_to_location)
                table = data.sheets()[0]
                if table.nrows < 3:
                    return Response("至少应包含一行数据！", status.HTTP_200_OK)
                for i in range(2, table.nrows):
                    datas = table.row_values(i)
                    if PhoneExists(str(datas[1])):
                        error_message.append("第"+str(i+1)+"行出现错误：手机号已存在！")
                        continue
                    school = School.objects.filter(school_name=datas[5]).first()
                    if school is None:
                        error_message.append("第"+str(i+1)+"行出现错误：学校不存在！")
                        continue
                    college = College.objects.filter(school=school, college_name=datas[6]).first()
                    if college is None:
                        error_message.append("第"+str(i+1)+"行出现错误：学院不存在！")
                        continue
                    major = Major.objects.filter(college=college, major_name=datas[7]).first()
                    if major is None:
                        error_message.append("第"+str(i+1)+"行出现错误：专业不存在！")
                        continue
                    belong_class = Class.objects.filter(major=major, class_name=datas[8]).first()
                    if belong_class is None:
                        error_message.append("第"+str(i+1)+"行出现错误：班级不存在！")
                        continue
                    # belong_class.major = major
                    # belong_class.save()
                    with transaction.atomic():
                        user_create = UserProfile()
                        user_create.set_password(settings.USER_DEFAULT_PASSWORD)
                        user_create.phone = str(datas[1])
                        user_create.email = str(datas[11])
                        user_create.sex = trans.sex_zh[str(datas[3])]
                        user_create.status = trans.status_zh[str(datas[10])]
                        user_create.username = str(datas[2])
                        user_create.user_type = "S"
                        user_create.real_name = str(datas[0])
                        user_create.save()
                        student_new = Student()
                        student_new.belong_class = belong_class
                        student_new.user = user_create
                        student_new.college = college
                        student_new.studentID = str(datas[4])
                        student_new.admission_date = str(datas[9]).replace('/','-')
                        student_new.save()
                        success += 1
                error_message.append("用户批量导入成功"+ str(success) +"条数据！")
            # 专家批量导入模板
            elif str(batch_type) == "5":
                data = xlrd.open_workbook(file_to_location)
                table = data.sheets()[0]
                if table.nrows < 3:
                    return Response("至少应包含一行数据！", status.HTTP_200_OK)
                
                for i in range(2, table.nrows):
                    datas = table.row_values(i)
                    if PhoneExists(str(datas[1])):
                        error_code = ErrorCode.parameter_error.value
                        error_message.append("第"+str(i+1)+"行出现错误：手机号已存在！")
                        continue
                    school = School.objects.filter(school_name=datas[5]).first()
                    if school is None:
                        error_message.append("第"+str(i+1)+"行出现错误：学校不存在！")
                        continue
                    with transaction.atomic():
                        user_create = UserProfile()
                        user_create.set_password(settings.USER_DEFAULT_PASSWORD)
                        user_create.phone = str(datas[1])
                        user_create.email = str(datas[7])
                        user_create.sex = trans.sex_zh[str(datas[3])]
                        user_create.status = trans.status_zh[str(datas[6])]
                        user_create.username = str(datas[2])
                        user_create.user_type = "E"
                        user_create.real_name = str(datas[0])
                        user_create.save()
                        expert_new = Expert()
                        expert_new.user = user_create
                        expert_new.school = school
                        expert_new.job_title = str(datas[4])
                        expert_new.save()
                        success += 1
                error_message.append("教授批量导入成功"+ str(success) +"条数据！")
            else:
                error_code = ErrorCode.parameter_error.value
                error_message.append("type参数错误!")
            self.response_format["error_code"] = error_code
            self.response_format["message"] = '\n'.join(error_message)
            return Response(self.response_format)
        except Exception as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.format_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)

# 班级管理相关视图

class ClassOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = ClassSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ClassOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Class.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, class_id=None):
        queryset = Class.objects.all()
        try:
            one = queryset.get(id = self.kwargs['class_id'])
            serializer = ClassListSerializer(one)
            self.response_format["data"] = serializer.data
        except Class.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '班级ID不存在'
        
        return Response(self.response_format)

class ClassListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Class.objects.all()
    serializer_class = ClassListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def get_queryset(self):
        queryset = Class.objects.all().order_by('-create_time')
        class_id = self.request.query_params.get('class_id', None)
        class_name = self.request.query_params.get('class_name', None)
        school_id = self.request.query_params.get('school_id', None)
        college_id = self.request.query_params.get('college_id', None)
        major_id = self.request.query_params.get('major_id', None)
        grade = self.request.query_params.get('grade', None)
        status = self.request.query_params.get('status', None)
        banned = [None,'']
        if class_id not in banned:
            queryset = queryset.filter(id=class_id)
        if class_name not in banned:
            queryset = queryset.filter(class_name=class_name)
        if school_id not in banned:
            queryset = queryset.filter(major__college__school__id=school_id)
        if college_id not in banned:
            queryset = queryset.filter(major__college__id=college_id)
        if major_id not in banned:
            queryset = queryset.filter(major__id=major_id)
        if grade not in banned:
            queryset = queryset.filter(grade__contains=grade)
        if status not in banned:
            queryset = queryset.filter(status=trans.class_status[status])
        
        return queryset

class ClassCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = ClassCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ClassCreateViewSet, self).__init__(**kwargs)
    def perform_create(self, serializer):
        class_new = serializer.save()
        class_new.status = trans.class_status[str(self.request.data['status'])]
        class_new.major_id = self.request.data['major_id']
        class_new.save()
    def create(self, request, *args, **kwargs):
        try:
            super(ClassCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "班级创建成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class ClassUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = ClassUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ClassUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return Class.objects.filter(id = self.kwargs['id'])

    def perform_update(self, serializer):
        class_modify = serializer.save()
        major_id = GetPostParaOrNone(self.request.data,"major_id")
        status = GetPostParaOrNone(self.request.data,"status")

        if major_id is not None:
            class_modify.major_id = major_id
        if status is not None:
            class_modify.status = trans.class_status[str(status)]

        class_modify.save()
        """
        teacher_modify = serializer.save()
        teacher_modify.college_id = 
        user_modify = 
        serializer.save()
        """
    def update(self, request, *args, **kwargs):
        try:
            super(ClassUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "班级更新成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class ClassBlockView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ClassBlockView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        """ try:
            return Teacher.objects.get(id=obj_id)
        except (Teacher.DoesNotExist, ValidationError):
            raise status.HTTP_400_BAD_REQUEST """
        try:
            return Class.objects.get(id = obj_id)
        except Class.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Class.objects.get(id = id)
            """ try:
                DemoConfig.objects.get(id=id)
            except (DemoConfig.DoesNotExist, ValidationError):
                raise status.HTTP_400_BAD_REQUEST """
        return True

    def post(self, request, *args, **kwargs):
        id_list = request.data['classes']
        instances = []
        try:
            status = trans.class_status[str(request.data['status'])]
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "status参数错误"
            return Response(self.response_format)
        for id in id_list:
            obj = self.get_object(obj_id=id)
            if obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '班级ID:'+str(id)+'不存在\n'
                continue
            obj.status = status
            obj.save()
            self.message += '班级ID:'+str(id)+'状态修改成功\n'
            instances.append(obj)
        serializer = ClassBlockSerializer(instances, many=True)
        self.response_format["message"] = self.message
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

class ClassAddView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ClassAddView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return Student.objects.get(user__id = obj_id)
        except Student.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        class_id = request.data['class_id']
        id_list = request.data['users']
        instances = []
        try:
            action = trans.student_class_action[str(request.data['action'])]
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "action参数错误"
            return Response(self.response_format)
        try:
            belong_class = Class.objects.get(id = class_id)
        except Class.DoesNotExist:
            self.response_format["message"] = "班级不存在"
            return Response(self.response_format)
        for id in id_list:
            obj = self.get_object(obj_id=id)
            if obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '用户ID:'+str(id)+'不存在\n'
                continue
            obj.belong_class = belong_class if action == 'add' else None
            obj.save()
            self.message += '用户ID:'+str(id)+'班级修改成功\n'
            instances.append(obj)
        self.response_format["message"] = self.message
        return Response(self.response_format)

# 课程相关视图

class CourseListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Course.objects.all()
    serializer_class = CourseListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def get_queryset(self):
        queryset = Course.objects.all().order_by('-create_time') if self.request.user.user_type == 'A' else Course.objects.filter(teacher=self.request.user.teacher).order_by('-create_time')
        course_id = self.request.query_params.get('course_id', None)
        course_name = self.request.query_params.get('course_name', None)
        keyword = self.request.query_params.get('keyword', None)
        course_type = self.request.query_params.get('course_type', None)
        teacher_name = self.request.query_params.get('teacher_name', None)
        student_id = self.request.query_params.get('student_id', None)
        status = self.request.query_params.get('status', None)
        banned = [None,'']
        if course_id not in banned:
            queryset = queryset.filter(id=course_id)
        if course_name not in banned:
            queryset = queryset.filter(course_name__icontains=course_name)
        if keyword not in banned:
            queryset = queryset.filter(course_name__icontains=keyword)
        if course_type not in banned:
            queryset = queryset.filter(course_type=trans.course_type[str(course_type)])
        if teacher_name not in banned:
            queryset = queryset.filter(teacher__user__real_name__icontains='teacher_name')
        if student_id not in banned:
            queryset = queryset.filter(student__user_id=student_id)
        if status not in banned:
            queryset = queryset.filter(status=trans.class_status[str(status)])
        
        return queryset

class CourseCreateViewSet(APIView):
    serializer_class = CourseCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(CourseCreateViewSet, self).__init__(**kwargs)

    def check_avatar(self, avatar_id):
        try:
            avatar = RichTextAttach.objects.get(id=avatar_id)
            return avatar
        except RichTextAttach.DoesNotExist:
            return None

    def post(self, request, format=None):
        request.data['price'] = GetPostParaOrNone(self.request.data, "price" , 0)
        serializer = CourseCreateSerializer(data=request.data, context={"request": request})
        if serializer.is_valid():
            with transaction.atomic():
                avatar_id = GetPostParaOrNone(self.request.data,"avatar_id")
                status = GetPostParaOrNone(self.request.data,"status")
                course = serializer.save()
                course.course_type = GetPostParaOrNone(self.request.data, "course_type", default='E')
                course.save()
                if course.course_type == 'E':
                    course.teacher_set.add(self.request.user.teacher)
                if status is not None and str(status) in trans.class_status.keys():
                    course.status = trans.class_status[str(status)]
                    course.save()
                if avatar_id is not None:
                    avatar = self.check_avatar(avatar_id)
                    if avatar is not None:
                        course.avatar_id = avatar_id
                        course.save()
                        self.message = '课程创建成功'
                        self.response_format["message"] = self.message
                        self.response_format["data"] = serializer.data
                    else:
                        self.response_format["error_code"] = ErrorCode.parameter_error.value
                        self.message = "参数错误"
                else:
                    self.message = '课程创建成功'
                    self.response_format["message"] = self.message
                    self.response_format["data"] = serializer.data
        else:
            print(serializer._errors)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.message = "参数错误"
        self.response_format["message"] = self.message
        return Response(self.response_format)

class CourseOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = CourseSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(CourseOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Course.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, course_id=None):
        queryset = Course.objects.all() if self.request.user.user_type == 'A' else Course.objects.filter(teacher=self.request.user.teacher)
        try:
            one = queryset.get(id = self.kwargs['course_id'])
            serializer = CourseSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Course.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '课程不存在'
        
        return Response(self.response_format)

class CourseUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = CourseUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(CourseUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return Course.objects.filter(id = self.kwargs['id'], teacher=self.request.user.teacher)

    def check_avatar(self, avatar_id):
        try:
            avatar = RichTextAttach.objects.get(id=avatar_id)
            return avatar
        except RichTextAttach.DoesNotExist:
            return None

    def perform_update(self, serializer):
        course = serializer.save()
        avatar_id = GetPostParaOrNone(self.request.data,"avatar_id")
        status = GetPostParaOrNone(self.request.data,"status")
        if status is not None and str(status) in trans.class_status.keys():
            course.status = trans.class_status[str(status)]
            course.save()
        if avatar_id is not None:
            avatar = self.check_avatar(avatar_id)
            if avatar is not None:
                course.avatar_id = avatar_id
                course.save()
            else:
                raise ValueError('')

    def update(self, request, *args, **kwargs):
        try:
            super(CourseUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "课程更新成功"
        except Exception as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

# 章节相关视图

class FullPagesPagination(pagination.PageNumberPagination):  
    page_size = 1000

class ChapterListAPIView(ListAPIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission|pm.StudentPermission]
    serializer_class = ChapterListSerializer
    model = serializer_class.Meta.model
    pagination_class = FullPagesPagination

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ChapterListAPIView, self).__init__(**kwargs)

    def get_queryset(self):
        course_id = self.kwargs['course_id']
        queryset = self.model.objects.filter(Q(course__id=course_id),Q(parent=None),Q(course__teacher=self.request.user.teacher)) if self.request.user.user_type == 'T' else self.model.objects.filter(Q(course__id=course_id),Q(parent=None))
        return queryset
    
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            self.response_format['data'] = serializer.data
            return Response(self.response_format)

        serializer = self.get_serializer(queryset, many=True)
        self.response_format['data'] = serializer.data
        return Response(self.response_format)


class CourseBlockView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(CourseBlockView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            res = Course.objects.get(id = obj_id) if self.request.user.user_type == 'A' else Course.objects.get(id=obj_id, teacher=self.request.user.teacher)
            return res
        except Course.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Course.objects.get(id = id)
        return True

    def post(self, request, *args, **kwargs):
        id_list = request.data['courses']
        try:
            status = GetPostParaOrNone(request.data, 'status', None)
            with transaction.atomic():
                for id in id_list:
                    obj = self.get_object(obj_id=id)
                    if obj == None:
                        raise LogicException(ErrorMsg.no_data)
                    obj.status = status
                    obj.save()
            self.response_format["message"] = '操作成功'
            return Response(self.response_format)
        except LogicException as e: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)

class ChapterBlockView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ChapterBlockView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            res = Chapter.objects.get(id = obj_id)
            return res
        except Chapter.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        id_list = request.data['ids']
        try:
            status = GetPostParaOrNone(request.data, 'status', None)
            with transaction.atomic():
                for id in id_list:
                    obj = self.get_object(obj_id=id)
                    if obj == None:
                        raise LogicException('数据不存在')
                    if self.request.user.user_type == 'T':
                        if not Course.objects.filter(id=obj.course.id, teacher=self.request.user.teacher).exists():
                            raise LogicException('无权操作数据')
                    obj.status = status
                    obj.save()
            self.response_format["message"] = '操作成功'
            return Response(self.response_format)
        except LogicException as e: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)

class ChapterUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = ChapterSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ChapterUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        ret = Chapter.objects.filter(id = self.kwargs['id']) if self.request.user.user_type == 'A' else Chapter.objects.filter(id = self.kwargs['id'], course__teacher=self.request.user.teacher)
        return ret

    def get_object1(self, obj_id):
        return Knowledge.objects.filter(id = obj_id).first()

    def perform_update(self, serializer):
        chapter = serializer.save()
        id_list = GetPostParaOrNone(self.request.data, "knowledges")
        if id_list != None:
            chapter.knowledge_set.clear()
            for id in id_list:
                obj = self.get_object1(obj_id=id)
                if obj == None:
                    continue
                chapter.knowledge_set.add(obj)
        serializer = ChapterSerializer(chapter)
        self.response_format["data"] = serializer.data
        
        return Response(self.response_format)
        

    def update(self, request, *args, **kwargs):
        try:
            super(ChapterUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "章节更新成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class CourseTeacherListAPIView(ListAPIView):
    serializer_class = CourseTeacherListSerializer
    model = serializer_class.Meta.model
    def get_serializer_context(self):
        context = super(CourseTeacherListAPIView, self).get_serializer_context()
        context.update({"course_id": self.kwargs['course_id']})
        return context
    def get_queryset(self):
        course_id = self.kwargs['course_id']
        queryset = self.model.objects.filter(Q(course__id=course_id))
        return queryset

class CourseAddStudentView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(CourseAddStudentView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return Student.objects.get(user__id = obj_id)
        except Student.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        course_id = request.data['course_id']
        id_list = request.data['users']
        try:
            action = trans.student_class_action[str(request.data['action'])]
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "action参数错误"
            return Response(self.response_format)
        try:
            course = Course.objects.get(id = course_id)
        except Course.DoesNotExist:
            self.response_format["message"] = "课程不存在"
            return Response(self.response_format)
        if action == 'add':
            for id in id_list:
                student = self.get_object(obj_id=id)
                if student == None:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '用户ID:'+str(id)+'不存在\n'
                    continue
                if course in student.course.all():
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '用户ID:'+str(id)+'已选课，请勿重新选课\n'
                    continue
                student.course.add(course_id)
                self.message += '用户ID:'+str(id)+'选课成功\n'
        else:
            for id in id_list:
                student = self.get_object(obj_id=id)
                if student == None:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '用户ID:'+str(id)+'不存在\n'
                    continue
                if course not in student.course.all():
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '用户ID:'+str(id)+'未选课，无法取消选课\n'
                    continue
                student.course.remove(course_id)
                self.message += '用户ID:'+str(id)+'退课成功\n'
        self.response_format["message"] = self.message
        return Response(self.response_format)

class CourseAddTeacherView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(CourseAddTeacherView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return Teacher.objects.get(user__id = obj_id)
        except Teacher.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        course_id = request.data['course_id']
        id_list = request.data['users']
        try:
            action = trans.student_class_action[str(request.data['action'])]
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "action参数错误"
            return Response(self.response_format)
        try:
            course = Course.objects.get(id = course_id)
        except Course.DoesNotExist:
            self.response_format["message"] = "课程不存在"
            return Response(self.response_format)
        if action == 'add':
            for id in id_list:
                teacher = self.get_object(obj_id=id)
                if teacher == None:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '教师ID:'+str(id)+'不存在\n'
                    continue
                if course in teacher.course.all():
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '教师ID:'+str(id)+'已授课，请勿重新授课\n'
                    continue
                teacher.course.add(course_id)
                self.message += '教师ID:'+str(id)+'授课成功\n'
        else:
            for id in id_list:
                teacher = self.get_object(obj_id=id)
                if teacher == None:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '教师ID:'+str(id)+'不存在\n'
                    continue
                if course not in teacher.course.all():
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '教师ID:'+str(id)+'未授课，无法取消授课\n'
                    continue
                teacher.course.remove(course_id)
                self.message += '教师ID:'+str(id)+'退课成功\n'
        self.response_format["message"] = self.message
        return Response(self.response_format)

class ObjectFileUploadView(APIView):
    parser_classes = (FormParser, MultiPartParser)
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ObjectFileUploadView, self).__init__(**kwargs)

    def post(self, request, format=None):
        now = datetime.now()
        timestampStr = now.strftime("%Y_%m_%d_%H_%M_%S_%f")
        up_file = request.FILES['file']
        batch_type = GetPostParaOrNone(self.request.data,"type")
        if batch_type is None:
            self.response_format["error_code"] = ErrorCode.missing_parameter.value
            self.response_format["message"] = '参数type缺失'
            return Response(self.response_format)
        file_to_location = 'BatchImportFiles/' +timestampStr + '_' + up_file.name
        destination = open(file_to_location, 'wb+')
        for chunk in up_file.chunks():
            destination.write(chunk)
        destination.close()

        success = 0
        error_code = 0
        error_message= []

        data = xlrd.open_workbook(file_to_location)
        table = data.sheets()[0]
        if table.nrows < 3:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '至少应包含一条数据'
            return Response(self.response_format)

        # 针对不同导入类型分别进行处理
        # 课程批量导入
        if str(batch_type) == "1":
            for i in range(2, table.nrows):
                datas = table.row_values(i)
                course_new = Course()
                course_new.course_name = datas[0]
                course_new.describe = datas[1]
                course_new.course_type = trans.course_type_zh[str(datas[2])]
                if datas[2] in trans.course_type_zh.keys() and datas[3] in trans.course_status_zh.keys():
                    course_new.course_type = trans.course_type_zh[str(datas[2])]
                    course_new.status = trans.course_status_zh[str(datas[3])]
                    course_new.course_type = 'E'
                    course_new.save()
                    course_new.teacher_set.add(self.request.user.teacher)
                    success += 1
                else:
                    error_message.append("第"+str(i+1)+"行出现错误：课程状态或课程类型错误")
                    error_code = ErrorCode.parameter_error.value
                    continue
            error_message.append("课程批量导入成功"+ str(success) +"条数据！")
            
        # 用户批量选课
        elif str(batch_type) == "2":
            for i in range(2, table.nrows):
                datas = table.row_values(i)
                course_find = Course.objects.get(course_name=datas[0], id=datas[1])
                student_find = Student.objects.get(user__real_name=datas[2], user__id=datas[3])
                if not course_find.exists():
                    error_message.append("第"+str(i+1)+"行出现错误：课程不存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                if not student_find.exists():
                    error_message.append("第"+str(i+1)+"行出现错误：教师不存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                if course_find in student_find.course.all():
                    error_message.append("第"+str(i+1)+"行出现错误：课程不存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                else:
                    student_find.course.add(datas[1])
                    success += 1
                
                
            error_message.append("用户批量选课成功"+ str(success) +"条数据！")
        # 课程批量添加授课教师
        elif str(batch_type) == "3":
            for i in range(2, table.nrows):
                datas = table.row_values(i)
                course_find = Course.objects.get(course_name=datas[0], id=datas[1])
                teacher_find = Teacher.objects.get(user__real_name=datas[2], user__id=datas[3])
                if not course_find.exists():
                    error_message.append("第"+str(i+1)+"行出现错误：课程不存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                if not teacher_find.exists():
                    error_message.append("第"+str(i+1)+"行出现错误：教师不存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                if course_find in teacher_find.course.all():
                    error_message.append("第"+str(i+1)+"行出现错误：课程不存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                else:
                    teacher_find.course.add(datas[1])
                    success += 1
            error_message.append("课程批量添加授课教师成功"+ str(success) +"条数据！")

        # 学校批量导入
        elif str(batch_type) == "4":
            for i in range(2, table.nrows):
                datas = table.row_values(i)
                school_new = School()
                school_find = School.objects.filter(school_name=datas[0])
                if school_find.exists():
                    error_message.append("第"+str(i+1)+"行出现错误：学校已存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                school_new.level = datas[1]
                school_new.school_name = datas[0]
                if datas[2] in trans.school_status_zh.keys():
                    school_new.status = trans.school_status_zh[str(datas[2])]
                    school_new.save()
                    success += 1
                else:
                    error_message.append("第"+str(i+1)+"行出现错误：学校状态错误")
                    error_code = ErrorCode.parameter_error.value
                    continue
            error_message.append("学校批量导入成功"+ str(success) +"条数据！")
            
        # 学院批量导入
        elif str(batch_type) == "5":
            for i in range(2, table.nrows):
                datas = table.row_values(i)
                college_new = College()
                school = School.objects.get_or_create(school_name=datas[1])[0]
                college_find = College.objects.filter(school=school, college_name=datas[0])
                if CollegeExists(school, datas[0]):
                    error_message.append("第"+str(i+1)+"行出现错误：学院已存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                college_new.school = school
                college_new.college_name = datas[0]
                if datas[2] in trans.school_status_zh.keys():
                    college_new.status = trans.school_status_zh[str(datas[2])]
                    college_new.save()
                    success += 1
                else:
                    error_message.append("第"+str(i+1)+"行出现错误：学院状态错误")
                    error_code = ErrorCode.parameter_error.value
                    continue
            error_message.append("学院批量导入成功"+ str(success) +"条数据！")
            
        # 专业批量导入
        elif str(batch_type) == "6":
            for i in range(2, table.nrows):
                datas = table.row_values(i)
                major_new = Major()
                school = School.objects.get_or_create(school_name=datas[1])[0]
                college = College.objects.filter(school=school).get_or_create(college_name=datas[2])[0]
                college.school = school
                college.save()
                major_find = Major.objects.filter(college=college, major_name=datas[0])
                if major_find.exists():
                    error_message.append("第"+str(i+1)+"行出现错误：专业已存在")
                    error_code = ErrorCode.parameter_error.value
                    continue
                major_new.college = college
                major_new.major_name = datas[0]
                if datas[3] in trans.school_status_zh.keys():
                    major_new.status = trans.school_status_zh[str(datas[3])]
                    major_new.save()
                    success += 1
                else:
                    error_message.append("第"+str(i+1)+"行出现错误：专业状态错误")
                    error_code = ErrorCode.parameter_error.value
                    continue
            error_message.append("专业批量导入成功"+ str(success) +"条数据！")

        # 批量导入选择题
        elif str(batch_type) == "7":
            for i in range(2, table.nrows):
                try:
                    datas = table.row_values(i)
                    if datas[0] not in trans.choice_ques_type:
                        raise Exception ("第"+str(i+1)+"行出现错误：题目类型不正确")
                    if datas[1] is None:
                        raise Exception("第"+str(i+1)+"行出现错误：题目名称不可为空")
                    if datas[6] == None or datas[6] == '':
                        raise Exception("第"+str(i+1)+"行出现错误：正确选项不可为空")

                    with transaction.atomic():
                        question_type = trans.choice_ques_type[datas[0]]
                        question_new = Question.addOne(question_type, self.request.user)
                        cd = ChoiceDetail.addOne(datas[1], question_new)
                        if datas[7] != None:
                            knowledge_list = datas[7].split('//')
                            pid = 0
                            obj = None
                            for name in knowledge_list:
                                query_set = Knowledge.objects.filter(knowledge_name=name)
                                if pid > 0:
                                    query_set.filter(parent_id=pid)
                                obj = query_set.first()
                                if obj == None:
                                    raise Exception("第"+str(i+1)+"行出现错误：知识点"+name+"不存在")
                            if obj != None:
                                question_new.knowledge.add(obj)

                        correct_answer = str(datas[6]).split(',')

                        def insert_option(str, index):
                            is_correct = index in correct_answer
                            OptionDetail.addOne(str, is_correct, cd, self.request.user)
                        
                        for i in range(2, 6):
                            if datas[i] != '':
                                insert_option(datas[i], str(i - 1))
                    success += 1
                except Exception as e:
                    traceback.print_exc()
                    error_message.append(str(e))
            error_message.append("选择题批量导入成功"+ str(success) +"条数据！")

        elif str(batch_type) == '8':
            for i in range(2, table.nrows):
                try:
                    datas = table.row_values(i)
                    if datas[0] not in trans.blank_ques_type:
                        raise Exception ("第"+str(i+1)+"行出现错误：题目类型不正确")
                    if datas[1] == '':
                        raise Exception("第"+str(i+1)+"行出现错误：题目名称不可为空")
                    if datas[2] == None or datas[2] == '':
                        raise Exception("第"+str(i+1)+"行出现错误：参考答案不可为空")
                    if datas[3] not in trans.ques_judge_type:
                        raise Exception("第"+str(i+1)+"行出现错误：判题规则不可为空")

                    with transaction.atomic():
                        question_type = trans.blank_ques_type[datas[0]]
                        judge_type = trans.ques_judge_type[datas[3]]
                        question_new = Question.addOne(question_type, self.request.user, judge_type=judge_type)

                        if datas[4] != None:
                            knowledge_list = datas[4].split('//')
                            pid = 0
                            obj = None
                            for name in knowledge_list:
                                query_set = Knowledge.objects.filter(knowledge_name=name)
                                if pid > 0:
                                    query_set.filter(parent_id=pid)
                                obj = query_set.first()
                                if obj == None:
                                    raise Exception("第"+str(i+1)+"行出现错误：知识点"+name+"不存在")
                            if obj != None:
                                question_new.knowledge.add(obj)
                        bd = BlankDetail.addOne(datas[1], datas[2], question_new)
                    success += 1
                except Exception as e:
                    traceback.print_exc()
                    error_message.append(str(e))
            error_message.append("简答题批量导入成功"+ str(success) +"条数据！")

        else:
            error_code = ErrorCode.parameter_error.value
            error_message.append("type参数错误!")
        self.response_format["error_code"] = error_code
        self.response_format["message"] = '\n'.join(error_message)
        return Response(self.response_format)

class SchoolListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = School.objects.all()
    serializer_class = SchoolListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def get_queryset(self):
        queryset = School.objects.all().order_by('-id')
        school_name = self.request.query_params.get('school_name', None)
        if school_name is not None:
            queryset = queryset.filter(school_name__icontains=school_name)
        # queryset = queryset.filter(status='N')
        
        return queryset

class SchoolCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = SchoolCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(SchoolCreateViewSet, self).__init__(**kwargs)
    def perform_create(self, serializer):
        serializer.save()
    def create(self, request, *args, **kwargs):
        try:
            if(SchoolExists(self.request.data['school_name'])):
                raise Exception('该学校已存在')
            super(SchoolCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "学校创建成功"
        except Exception as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class SchoolUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = SchoolUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(SchoolUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return School.objects.filter(id = self.kwargs['id'])

    def perform_update(self, serializer):
        serializer.save()
        """
        teacher_modify = serializer.save()
        teacher_modify.college_id = 
        user_modify = 
        serializer.save()
        """
    def update(self, request, *args, **kwargs):
        try:
            super(SchoolUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "学校更新成功"
        except Exception as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class SchoolOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = SchoolListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(SchoolOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return School.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, school_id=None):
        queryset = School.objects.all()
        try:
            one = queryset.get(id = self.kwargs['school_id'])
            serializer = SchoolListSerializer(one)
            self.response_format["data"] = serializer.data
        except School.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '学校ID不存在'
        
        return Response(self.response_format)

class CollegeListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = College.objects.all()
    serializer_class = CollegeListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def get_queryset(self):
        queryset = College.objects.all().order_by('-id')
        keyword = self.request.query_params.get('keyword', None)
        school_id = self.request.query_params.get('school_id', None)
        college_name = self.request.query_params.get('college_name', None)
        if keyword is not None:
            queryset = queryset.filter(college_name__icontains=keyword)
        if school_id is not None:
            queryset = queryset.filter(school_id=school_id)
        if college_name is not None and college_name != '':
            queryset = queryset.filter(college_name__icontains=college_name)
        # queryset = queryset.filter(status='N')
        
        return queryset

class CollegeCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = CollegeCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(CollegeCreateViewSet, self).__init__(**kwargs)
    def perform_create(self, serializer):
        college_new = serializer.save()
        college_new.school_id = self.request.data['school_id']
        college_new.save()
    def create(self, request, *args, **kwargs):
        try:
            super(CollegeCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "学院创建成功"
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)

class CollegeUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = CollegeUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(CollegeUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return College.objects.filter(id = self.kwargs['id'])

    def perform_update(self, serializer):
        serializer.save()
    def update(self, request, *args, **kwargs):
        try:
            super(CollegeUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "学院更新成功"
        except Exception as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class CollegeOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = CollegeListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(CollegeOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return College.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, college_id=None):
        queryset = College.objects.all()
        try:
            one = queryset.get(id = self.kwargs['college_id'])
            serializer = CollegeListSerializer(one)
            self.response_format["data"] = serializer.data
        except College.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '学院ID不存在'
        
        return Response(self.response_format)

class MajorListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Major.objects.all()
    serializer_class = MajorListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def get_queryset(self):
        queryset = Major.objects.all()
        keyword = self.request.query_params.get('keyword', None)
        college_id = self.request.query_params.get('college_id', None)
        if keyword is not None:
            queryset = queryset.filter(major_name__icontains=keyword)
        if college_id is not None:
            queryset = queryset.filter(college_id=college_id)
        queryset = queryset.order_by('-create_time')
        
        return queryset

class MajorCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = MajorCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(MajorCreateViewSet, self).__init__(**kwargs)
    def perform_create(self, serializer):
        major_new = serializer.save()
        major_new.college_id = self.request.data['college_id']
        major_new.save()
    def create(self, request, *args, **kwargs):
        try:
            super(MajorCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "专业创建成功"
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)

class MajorUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = MajorUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(MajorUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return Major.objects.filter(id = self.kwargs['id'])

    def perform_update(self, serializer):
        serializer.save()
    def update(self, request, *args, **kwargs):
        try:
            super(MajorUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "专业更新成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class MajorOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = MajorListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(MajorOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Major.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, major_id=None):
        queryset = Major.objects.all()
        try:
            one = queryset.get(id = self.kwargs['major_id'])
            serializer = MajorListSerializer(one)
            self.response_format["data"] = serializer.data
        except Major.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '专业ID不存在'
        
        return Response(self.response_format)

# class KnowledgeListPagination(pagination.PageNumberPagination):
#     page_size = 100
#     page_size_query_param = 'page_size'
#     max_page_size = 1000

class KnowledgeListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = KnowledgeListSerializer
    # pagination_class = KnowledgeListPagination
    model = serializer_class.Meta.model
    queryset = Knowledge.objects.all()
    pagination_class = FullPagesPagination

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(KnowledgeListViewSet, self).__init__(**kwargs)

    def get_queryset(self):
        parent_id = self.request.query_params.get('parent_id', None)
        self.queryset = self.queryset.filter(parent_id=parent_id)
        return self.queryset

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            self.response_format['data'] = serializer.data
            return Response(self.response_format)

        serializer = self.get_serializer(queryset, many=True)
        self.response_format['data'] = serializer.data
        return Response(self.response_format)

class KnowledgeAddView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.ExpertPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(KnowledgeAddView, self).__init__(**kwargs)

    def check_knowledge(self, knowledge_id):
        try:
            knowledge = Knowledge.objects.get(id = knowledge_id)
            return knowledge
        except Knowledge.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        try:
            knowledge_id = request.data['knowledge_id']
            knowledge_name = request.data['knowledge_name']
        except: 
            self.response_format["error_code"] = ErrorCode.missing_parameter.value
            self.response_format["message"] = "缺少参数"
            return Response(self.response_format)
        try:
            action = trans.chapter_action[str(request.data['action'])]
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "action参数错误"
            return Response(self.response_format)
        if action == "add":
            knowledge = self.check_knowledge(knowledge_id)

            knowledge_new = Knowledge()
            knowledge_new.knowledge_name = knowledge_name
            knowledge_new.parent = knowledge
            knowledge_new.save()
            self.message += '知识点创建成功\n'
        elif action == "remove":
            knowledge = self.check_knowledge(knowledge_id)
            if knowledge == None:
                self.response_format["message"] = "知识点不存在"
                return Response(self.response_format)
            knowledge.delete()
            self.message += '知识点删除成功\n'
        else:
            knowledge = self.check_knowledge(knowledge_id)
            if knowledge == None:
                self.response_format["message"] = "知识点不存在"
                return Response(self.response_format)
            knowledge.knowledge_name = knowledge_name
            knowledge.save()
            self.message += '知识点修改成功\n'
        self.response_format["message"] = self.message
        return Response(self.response_format)

class KnowledgeSearchListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Knowledge.objects.all()
    serializer_class = KnowledgeSearchListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission|pm.ExpertPermission]

    def get_queryset(self):
        queryset = Knowledge.objects.all()
        keyword = self.request.query_params.get('keyword', None)
        if keyword is not None:
            queryset = queryset.filter(knowledge_name__icontains = keyword)
        
        return queryset

class ImageUploadViewSet(APIView):
    parser_classes = (MultiPartParser, )
    serializer_class = ImageUploadSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission|pm.StudentPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ImageUploadViewSet, self).__init__(**kwargs)

    def post(self, request, format=None):
        try:
            serializer = ImageUploadSerializer(data=request.data, context={"request": request})
            if serializer.is_valid():
                serializer.save()
                self.message = '文件上传成功'
                self.response_format["message"] = self.message
                self.response_format["data"] = serializer.data
            else:
                logger.error(serializer.errors)
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message = str(serializer.errors)
            self.response_format["message"] = self.message
            return Response(self.response_format)
        except Exception as e:
            logger.error(str(e))
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.comon_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)

class InstanceStartUpView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission | pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(InstanceStartUpView, self).__init__(**kwargs)

    def get_object(self, obj_id):
        try:
            ret = Instance.objects.get(id=obj_id) if self.request.user.user_type == 'A' else Instance.objects.get(
                id=obj_id, environment__experiment__teacher=self.request.user.teacher)
            return ret
        except Instance.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Instance.objects.get(id=id)
        return True

    def post(self, request, *args, **kwargs):
        try:
            id_list = request.data['instances']
            instances = []
            for id in id_list:
                obj = self.get_object(obj_id=id)
                if obj == None:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '实例ID:' + str(id) + '不存在\n'
                    continue
                ci = CloudInstance()
                try:
                    if ci.start([obj.instanceId]):
                        # obj.status = "N"
                        # obj.save()
                        self.message += '实例ID:' + str(id) + '开机成功\n'
                        instances.append(obj)
                    else:
                        self.response_format["error_code"] = ErrorCode.parameter_error.value
                        self.message += '实例ID:' + str(id) + '开机失败\n'
                        continue
                except TencentCloudSDKException as e:
                        if str(e).__contains__("Request-sent"):
                            self.response_format["message"] = "正在开机中"
                        else:
                            self.response_format["message"] = str(e.get_message())
                        return Response(self.response_format)
            self.response_format["message"] = self.message
            return Response(self.response_format)
        except Exception as e:
            traceback.print_exc()
            self.response_format["message"] = str(e)
            return Response(self.response_format)

class InstanceShutdownView(APIView):

    # serializer_class = InstanceStatusSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(InstanceShutdownView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            ret = Instance.objects.get(id = obj_id) if self.request.user.user_type == 'A' else Instance.objects.get(id = obj_id, environment__experiment__teacher=self.request.user.teacher)
            return ret
        except Instance.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Instance.objects.get(id = id)
        return True

    def post(self, request, *args, **kwargs):
        try:
            id_list = request.data['instances']
        # except Exception as e:
        #     traceback.print_exc()
        #     self.response_format["error_code"] = ErrorCode.parameter_error.value
        #     self.response_format["message"] = str(e)
        #     return Response(self.response_format)
            instances = []
            for id in id_list:
                obj = self.get_object(obj_id=id)
                print(obj)
                if obj == None:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '实例ID:'+str(id)+'不存在\n'
                    continue
                if obj.status == "C":
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '实例ID:'+str(id)+'已失效\n'
                    continue
                ci = CloudInstance(instanceid=obj.instanceId)
                instanceIds = [obj.instanceId]
                print("---------------")
                print(instanceIds)
                print("---------------")
                if ci.batch_shutdown(instanceIds):
                    self.message += '实例ID:'+str(id)+'关机成功\n'
                    instances.append(obj)
                else:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '实例ID:'+str(id)+'关机失败\n'
                    continue
            # serializer = InstanceStatusSerializer(instances, many=True)
            self.response_format["message"] = self.message
            self.response_format["data"] = []
            # self.response_format["data"] = serializer.data
            return Response(self.response_format)
        except TencentCloudSDKException as e:
            if str(e).__contains__("Request-sent"):
                self.response_format["message"] = "正在关机中"
            else:
                self.response_format["message"] = str(e.get_message())
            return Response(self.response_format)
        except Exception as e:
            traceback.print_exc()
            self.response_format["message"] = str(e)
            return Response(self.response_format)


class EnvironmentIssueView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(EnvironmentIssueView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            res = Environment.objects.get(id = obj_id) if self.request.user.user_type=='A' else Environment.objects.get(id = obj_id, experiment__teacher=self.request.user.teacher)
            return res
        except Environment.DoesNotExist:
            return None

    def get_course(self, obj_id):
        try:
            res = Course.objects.get(id = obj_id) if self.request.user.user_type=='A' else Course.objects.get(id = obj_id, teacher=self.request.user.teacher)
            return res
        except Course.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Environment.objects.get(id = id)
        return True

    def post(self, request, *args, **kwargs):
        try:
            environment_id = request.data['environment_id']
            course_id = request.data['course_id']
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)
        course = self.get_course(obj_id=course_id)
        if course is None:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "课程不存在"
            return Response(self.response_format)
        environment = self.get_object(obj_id=environment_id)
        if environment is None:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "实验环境不存在"
            return Response(self.response_format)
        try:
            with transaction.atomic():
                students = course.student_set
                experiment = environment.experiment
                experiment.course.add(course)
                logger.error('students: {}'.format(students))
                for student in students.all():
                    experiment.student.add(student)
            self.message += '实例下发成功\n'
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.message += '实例下发失败\n'
        self.response_format["message"] = self.message
        return Response(self.response_format)
        
class EnvironmentListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Environment.objects.all()
    serializer_class = EnvironmentListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def get_queryset(self):
        queryset = Environment.objects.all() if self.request.user.user_type == 'A' else Environment.objects.filter(experiment__teacher=self.request.user.teacher)
        # environment_id = self.request.query_params.get('environment_id', None)
        id = self.request.query_params.get('id', None)
        environment_name = self.request.query_params.get('environment_name', None)
        image_id = self.request.query_params.get('image_id', None)
        image_name = self.request.query_params.get('image_name', None)
        subnet_name = self.request.query_params.get('subnet_name', None)
        is_open = self.request.query_params.get('is_open', None)
        banned = [None,'']
        if id not in banned:
            queryset = queryset.filter(id=id)
        if environment_name not in banned:
            queryset = queryset.filter(environment_name__icontains=environment_name)
        if image_id not in banned:
            queryset = queryset.filter(image__id=image_id)
        if image_name not in banned:
            queryset = queryset.filter(image__image_name__icontains=image_name)
        if subnet_name not in banned:
            queryset = queryset.filter(subnet_name__icontains=subnet_name)
        # if str(is_open) in ['1', '2']:
        #     queryset = queryset.filter(is_open=trans.is_open[str(is_open)])
        if str(is_open) in ['T', 'F']:
            queryset = queryset.filter(is_open=str(is_open))
        ids = Experiment.objects.filter(Q(show='T') & Q(environment_id__isnull=False)).values_list('environment_id', flat=True)
        logger.error("实验环境id集合{}".format(ids))
        queryset = queryset.filter(id__in=ids)
        logger.error("返回的实验环境集合{}".format(queryset))
        return queryset.order_by('-id')

class FuzzySearchImageView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(FuzzySearchImageView, self).__init__(**kwargs)

    def get(self, request, *args, **kwargs):
        keyword = self.request.query_params.get('keyword', '')
        is_basic = self.request.query_params.get('is_basic', '')
        if str(is_basic) == "1":
            images_res = Image.objects.filter(Q(image_name__icontains=keyword), Q(owner__user_type="A"))[:20] if self.request.user.user_type == 'A' else Image.objects.filter(Q(image_name__icontains=keyword), (Q(owner__user_type="A")|Q(owner=self.request.user)))[:20]
        else:
            images_res = Image.objects.filter(image_name__icontains=keyword)[:20] if self.request.user.user_type == 'A' else Image.objects.filter(Q(image_name__icontains=keyword), Q(owner=self.request.user))[:20]
        serializer = FuzzySearchImageSerializer(images_res, many=True)
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

class DescImportImageViewSet(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(DescImportImageViewSet, self).__init__(**kwargs)
    
    def get_object(self, id):
        try:
            return Image.objects.get(id=id)
        except Image.DoesNotExist:
            return None

    def post(self, request, format=None):
            try:
                id = GetPostParaOrNone(self.request.data, "id")
                if id is None:
                    raise Exception('参数错误')
                image = self.get_object(id)
                if image is None:
                    raise Exception('数据不存在')
                # import file from cos to cvm images
                ci = CloudImage()
                importResp = ci.DescribeCustomImageTask(ImageName = image.image_name)
                logger.error('ImageName: {}, importResp:{}'.format(image, importResp))
                if importResp.TotalCount == 0:
                    image.import_status = 3
                    image.import_msg = '导入失败, 请参阅：https://cloud.tencent.com/document/product/213/4945#%E5%AF%BC%E5%85%A5%E5%87%86%E5%A4%87'
                else:
                    task = importResp.ImageTaskSet[0]
                    if task['State'] == 'SUCCESS':
                        image.import_status = 2
                        image.import_msg = task['Message']
                    else:
                        image.import_status = 2
                        image.import_msg = task['Message']
                image.save()
                self.response_format["message"] = image.import_msg
                return Response(self.response_format)
            except Exception as err:
                logger.error(err)
                self.response_format["error_code"] = ErrorCode.comon_error.value
                self.response_format["message"] = str(err)
                return Response(self.response_format)

class DescImportImageViewSet(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(DescImportImageViewSet, self).__init__(**kwargs)
    
    def get_object(self, id):
        try:
            return Image.objects.get(id=id)
        except Image.DoesNotExist:
            return None

    def post(self, request, format=None):
            try:
                id = GetPostParaOrNone(self.request.data, "id")
                if id is None:
                    raise Exception('参数错误')
                image = self.get_object(id)
                if image is None:
                    raise Exception('数据不存在')
                # import file from cos to cvm images
                ci = CloudImage()
                importResp = ci.DescribeCustomImageTask(ImageName = image.image_name)
                logger.error('ImageName: {}, importResp:{}'.format(image, importResp))
                if importResp.TotalCount == 0:
                    image.import_status = 3
                    image.import_msg = '导入失败'
                else:
                    task = importResp.ImageTaskSet[0]
                    if task['State'] == 'SUCCESS':
                        image.import_status = 2
                        image.import_msg = task['Message']
                    else:
                        image.import_status = 2
                        image.import_msg = task['Message']
                image.save()
                self.response_format["message"] = image.import_msg
                return Response(self.response_format)
            except Exception as err:
                logger.error(err)
                self.response_format["error_code"] = ErrorCode.comon_error.value
                self.response_format["message"] = str(err)
                return Response(self.response_format)

class ImageImportViewSet(APIView):
    serializer_class = CvmImageImportSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ImageImportViewSet, self).__init__(**kwargs)
    
    def get_object(self, id):
        try:
            return Image.objects.get(id = id)
        except Image.DoesNotExist:
            return None

    def post(self, request, format=None):
        try:
            id = GetPostParaOrNone(self.request.data, "id")
            logger.error('id:{}'.format(id))
            if id is None:
                raise Exception('参数错误')
            image = self.get_object(id)
            logger.error('id:{}'.format(image))
            if image is None:
                raise Exception('数据不存在')
            # import file from cos to cvm images
            cc = CosClient()
            ImageUrl = cc.get_presigned_url(image.image_url)
            ci = CloudImage()
            importResp = ci.importImage(image.image_name, image.opration_system, image.version, ImageUrl, Architecture=image.architecture)
            logger.error('importResp:{}'.format(importResp))
            if not importResp.RequestId:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.response_format["message"] = "镜像导入失败"
                image.import_status = 3
                image.save()
                return Response(self.response_format)
            image.import_status = 1
            image.request_id = importResp.RequestId
            if hasattr(importResp, 'TaskId'):
                image.task_id = importResp.TaskId
            if hasattr(importResp, 'ImageId'):
                image.imageId = importResp.ImageId
            image.save()
            self.message = '镜像导入提交完成'
            self.response_format["message"] = self.message
            return Response(self.response_format)
        except Exception as err:
            logger.error(err)
            self.response_format["error_code"] = ErrorCode.comon_error.value
            self.response_format["message"] = str(err)
            return Response(self.response_format) 

class ImageCreateImportViewSet(APIView):
    serializer_class=CvmImageCreateImportSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ImageCreateImportViewSet, self).__init__(**kwargs)

    def post(self, request, format=None):
        try:
            with transaction.atomic():
                serializer = CvmImageCreateImportSerializer(data=request.data, context={"request": request})
                if not serializer.is_valid():
                    raise Exception(serializer._errors)
                image = serializer.save()
                ci = CloudImage()
                cc = CosClient()
                imageUrl = cc.get_presigned_url(image.image_url)
                importResp = ci.importImage(image.image_name, image.opration_system, image.version, imageUrl, Architecture=image.architecture)
                logger.error('importResp:{}'.format(importResp))
                if not importResp.RequestId:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.response_format['data'] = importResp
                    self.response_format["message"] = "镜像导入失败"
                    image.import_status = 3
                    image.save()
                    return Response(self.response_format)
                image.import_status = 1
                image.request_id = importResp.RequestId
                image.owner = request.user
                if hasattr(importResp, 'TaskId'):
                    image.task_id = importResp.TaskId
                if hasattr(importResp, 'ImageId'):
                    image.imageId = importResp.ImageId
                image.save()
                self.message = '镜像导入提交完成'
                self.response_format["message"] = self.message
                return Response(self.response_format)
        except TencentCloudSDKException as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.comon_error.value
            self.response_format["message"] = str('镜像无法识别，请确认镜像格式，或是否成功预装cloud-init')
            return Response(self.response_format)
        except Exception as err:
            logger.error(err)
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.comon_error.value
            self.response_format["message"] = str(err)
            return Response(self.response_format)

class CvmImageUploadViewSet(APIView):
    parser_classes = (MultiPartParser, )
    serializer_class = CvmImageImportSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(CvmImageUploadViewSet, self).__init__(**kwargs)

    def post(self, request, format=None):
        try:
            serializer = CvmImageImportSerializer(data=request.data, context={"request": request})
            if serializer.is_valid():
                image_type = GetPostParaOrNone(self.request.data, "image_type")
                ImageName = GetPostParaOrNone(self.request.data, "image_name")
                OsType = GetPostParaOrNone(self.request.data, "operation_system")
                Architecture = GetPostParaOrNone(self.request.data, "architecture")
                OsVersion = GetPostParaOrNone(self.request.data, "version")
                image = serializer.save()
                if image_type is not None and str(image_type) in trans.image_type.keys():
                    image.image_type = trans.image_type[str(image_type)]
                    image.save()
                ci = CloudImage()
                up_file = request.FILES['image_source']
                image_cos_key = '{}/{}/{}/{}.{}'.format(datetime.today().year, datetime.today().month, datetime.today().day, uuid.uuid4(), up_file.name.split('.')[-1])
                # store file to local path
                file_to_location =  os.path.dirname(os.path.dirname(__file__)) + '/BatchImportFiles/' + str(uuid.uuid4()) + '.' + up_file.name.split('.')[-1]
                destination = open(file_to_location, 'wb+')
                for chunk in up_file.chunks():
                    destination.write(chunk)
                destination.close() 
                logger.error('write file:{}'.format(file_to_location))
                # upload file to cos
                ci.uploadImage(file_to_location, image_cos_key)
                logger.error('upload image:{}'.format(ci))
                imageurl = image_cos_key
                if not imageurl:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.response_format["message"] = "镜像上传失败"
                    return Response(self.response_format)
                ci.imageurl = imageurl
                image.image_url = imageurl
                image.save()
                # import file from cos to cvm images
                # ci.imageid = imageid
                # image.image_id = imageid
                image.owner = request.user
                image.save()
                self.message = '镜像导入成功'
                self.response_format["message"] = self.message
                self.response_format["data"] = serializer.data
                return Response(self.response_format)
            else:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message = "参数错误"
                return Response(self.response_format)
        except Exception as err:
            logger.error(err)
            self.response_format["error_code"] = ErrorCode.comon_error.value
            self.response_format["message"] = str(err)
            return Response(self.response_format)

class CosUploadStsView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(CosUploadStsView, self).__init__(**kwargs)
    def get(self, request, *args, **kwargs):
        cos = CosClient()
        self.response_format["data"] = cos.get_credential()
        return Response(self.response_format)

class CosSignView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(CosSignView, self).__init__(**kwargs)
    def get(self, request, *args, **kwargs):
        key = GetPostParaOrNone(request.GET, 'key')
        cos = CosClient()
        self.response_format["data"] = cos.get_presigned_url(key)
        return Response(self.response_format)

class ImageModifyFirstView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ImageModifyFirstView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return Image.objects.get(id = obj_id) if self.request.user.user_type == 'A' else Image.objects.get(Q(id = obj_id),Q(owner=self.request.user))
        except Image.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Image.objects.get(id = id)
        return True

    def post(self, request, *args, **kwargs):
        try:
            image_id = request.data['image_id']
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)
        image = self.get_object(obj_id=image_id)
        if image is None:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "镜像不存在"
            return Response(self.response_format)
        
        try:
            ci = CloudImage(imageid=image.imageId)
            instanceid = ci.issue()
            if instanceid:
                instance = TempInstance()
                instance.instanceId = instanceid
                instance.image = image
                instance.user = request.user
                instance.save()
                self.message = '实例创建成功\n'
                self.response_format["data"] = {"instance_id":instance.id,"instanceid":instanceid}
            else:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message = '实例创建失败\n'
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.message = '实例创建失败\n'
        self.response_format["message"] = self.message
        return Response(self.response_format)

class ImageModifySecondView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ImageModifySecondView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return TempInstance.objects.get(Q(id = obj_id),Q(user=self.request.user))
        except TempInstance.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            TempInstance.objects.get(id = id)
        return True

    def post(self, request, *args, **kwargs):
        try:
            instance_id = request.data['instance_id']
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)
        instance = self.get_object(obj_id=instance_id)
        if instance is None:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "实例不存在"
            return Response(self.response_format)
        
        try:
            ci = CloudInstance(instanceid=instance.instanceId)
            do_shutdown = ci.shutdown()
            if do_shutdown:
                self.message = '实例关机成功\n'
            else:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message = '实例关机失败\n'
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.message = '实例关机失败\n'
        self.response_format["message"] = self.message
        return Response(self.response_format)

class ImageModifyThirdView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ImageModifyThirdView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return TempInstance.objects.get(Q(id = obj_id),Q(user=self.request.user))
        except TempInstance.DoesNotExist:
            return None

    def get_image(self, obj_id):
        try:
            return Image.objects.get(id = obj_id) if self.request.user.user_type == 'A' else Image.objects.get(Q(id = obj_id),Q(owner=self.request.user))
        except Image.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            TempInstance.objects.get(id = id)
        return True

    def post(self, request, *args, **kwargs):
        try:
            instance_id = request.data['instance_id']
            image_name = request.data['image_name']
            image_id = request.data['image_id']
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)
        instance = self.get_object(obj_id=instance_id)
        if instance is None:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "实例不存在"
            return Response(self.response_format)
        image_old = self.get_image(obj_id=image_id)
        if image_old is None:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "镜像不存在"
            return Response(self.response_format)
        try:
            ci = CloudInstance(instanceid=instance.instanceId)
            imageId = ci.save()
            if imageId:
                image_old.imageId = imageId
                image_old.image_name = image_name
                image_new.save()
                self.message = '镜像修改成功\n'
            else:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message = '镜像修改失败\n'
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.message = '镜像修改失败\n'
        self.response_format["message"] = self.message
        return Response(self.response_format)

class ImageOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = ImageSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ImageOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Image.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, image_id=None):
        queryset = Image.objects.all() if request.user.user_type == 'A' else Image.objects.filter(Q(owner__user_type="A")|Q(owner=self.request.user))
        try:
            one = queryset.get(id = self.kwargs['image_id'])
            serializer = ImageSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Image.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '实验环境ID不存在'
        
        return Response(self.response_format)

class ImageRemoveView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ImageRemoveView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return Image.objects.get(id = obj_id) if self.request.user.user_type == 'A' else Image.objects.get(Q(id = obj_id),Q(owner=self.request.user))
        except Image.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Image.objects.get(id = id)
            """ try:
                DemoConfig.objects.get(id=id)
            except (DemoConfig.DoesNotExist, ValidationError):
                raise status.HTTP_400_BAD_REQUEST """
        return True

    def post(self, request, *args, **kwargs):
        id_list = request.data['images']
        instances = []
        for id in id_list:
            obj = self.get_object(obj_id=id)
            if obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '镜像ID:'+str(id)+'不存在\n'
                continue
            obj.status = 'C'
            obj.save()
            self.message += '镜像ID:'+str(id)+'状态修改成功\n'
            instances.append(obj)
        serializer = ImageRemoveSerializer(instances, many=True)
        self.response_format["message"] = self.message
        self.response_format["data"] = serializer.data
        return Response(self.response_format)

class ExperimentScoreListAPIView(ListAPIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    serializer_class = ExperimentScoreListSerializer
    model = serializer_class.Meta.model
    def get_queryset(self):
        course_id = self.kwargs['course_id']
        student_id = self.kwargs['student_id']
        queryset = self.model.objects.filter(Q(experiment__course__id=course_id),Q(experiment__course__teacher=self.request.user.teacher),Q(student__user__id=student_id))
        return queryset

class ExamScoreListAPIView(ListAPIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    serializer_class = ExamScoreListSerializer
    model = serializer_class.Meta.model
    def get_queryset(self):
        course_id = self.kwargs['course_id']
        student_id = self.kwargs['student_id']
        queryset = self.model.objects.filter(Q(exam__course__id=course_id),Q(exam__course__teacher=self.request.user.teacher),Q(student__user__id=student_id))
        return queryset

class ExperimentCreateViewSet(APIView):
    serializer_class = ExperimentCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ExperimentCreateViewSet, self).__init__(**kwargs)

    def get_object1(self, obj_id):
        try:
            return Knowledge.objects.get(id = obj_id)
        except Knowledge.DoesNotExist:
            return None

    def post(self, request, format=None):
        serializer = ExperimentCreateSerializer(data=request.data, context={"request": request})
        if serializer.is_valid():
            try:
                with transaction.atomic():
                    knowledges = GetPostParaOrNone(self.request.data,"knowledges")
                    experiment = serializer.save()
                    experiment.teacher.add(self.request.user.teacher)
                    if knowledges != None:
                        for id in knowledges:
                            obj = self.get_object1(obj_id=id)
                            if obj == None:
                                continue
                            experiment.knowledge.add(obj)
                self.message = '实验创建成功'
                self.response_format["message"] = self.message
                self.response_format["data"] = serializer.data
            except Exception as e:
                logger.error(e)
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message = '参数错误'
        else:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.message = "参数错误"
        self.response_format["message"] = self.message
        return Response(self.response_format)

class ExperimentUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = ExperimentCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ExperimentUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        ret = Experiment.objects.filter(id = self.kwargs['id']) if self.request.user.user_type == 'A' else Experiment.objects.filter(id = self.kwargs['id'], teacher=self.request.user.teacher)
        return ret

    def get_object1(self, obj_id):
        try:
            return Knowledge.objects.get(id = obj_id)
        except Knowledge.DoesNotExist:
            return None

    def perform_update(self, serializer):
        experiment = serializer.save()
        id_list = GetPostParaOrNone(self.request.data,"knowledges")
        if id_list != None:
            experiment.knowledge.clear()
            for id in id_list:
                obj = self.get_object1(obj_id=id)
                if obj == None:
                    continue
                experiment.knowledge.add(obj)
        serializer = ExperimentCreateSerializer(experiment)
        self.response_format["data"] = serializer.data
        
        return Response(self.response_format)
        

    def update(self, request, *args, **kwargs):
        try:
            super(ExperimentUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "章节更新成功"
        except Exception as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)
class EnvironmentUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = EnvironmentCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission|pm.AdminPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(EnvironmentUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        user = self.request.user
        print("当前用户类型是-------->" + user.user_type)
        if (user is None or user.user_type == 'S'):
            raise LogicException("请使用老师或管理员账号进行操作")
        if (user.user_type == 'T'):
            ret = Environment.objects.filter(id = self.kwargs['id'], experiment__teacher=self.request.user.teacher)
        else:
            ret = Environment.objects.filter(id = self.kwargs['id'])
        # ret = Environment.objects.filter(id = self.kwargs['id'], experiment__teacher=self.request.user.teacher)
        return ret

    def get_object1(self, obj_id):
        try:
            return Image.objects.get(Q(id = obj_id))
        except Image.DoesNotExist:
            return None

    def perform_update(self, serializer):
        environment = serializer.save()
        # id_list = GetPostParaOrNone(self.request.data,"images")
        ids = GetPostParaOrNone(self.request.data,"images")
        environment_name = GetPostParaOrNone(self.request.data,"environment_name")
        subnet_name = GetPostParaOrNone(self.request.data,"subnet_name")
        cidr_block = GetPostParaOrNone(self.request.data,"cidr_block")
        is_open = GetPostParaOrNone(self.request.data,"is_open")
        security_group = GetPostParaOrNone(self.request.data,"security_group")
        experiment = Experiment.objects.get(id=GetPostParaOrNone(self.request.data, "experiment_id"))
        environment_name=experiment.experiment_name
        print(f"实验环境名称：{environment_name}")
        # trans.is_open[str(self.request.data['is_open'])]
        if environment_name != None:
            environment.environment_name = str(environment_name)
        if subnet_name != None:
            environment.subnet_name = str(subnet_name)
        if cidr_block != None:
            environment.cidr_block = str(cidr_block)
        if is_open != None:
            environment.is_open = is_open
        if security_group != None:
            environment.security_group = security_group
        environment.save()
        # if id_list != None:
        print(f"image_ids：{ids}")
        if ids and len(ids) == 1 and ids[0] is not None:
            if experiment.experiment_type == "single":
               environment.image.clear()
        if ids:
            if ids[0] is not None and ids[0] != '':
                experiment.experiment_type = 'single'
                pii = self.get_object1(obj_id=int(experiment.primary_image_id))
                if pii:
                    environment.image.remove(pii)
                experiment.primary_image_id = int(ids[0])
                experiment.save()
                ig = self.get_object1(obj_id=int(ids[0]))
                if ig:
                    environment.image.add(ig)
            if len(ids) > 1:
               experiment.experiment_type = 'double'
               experiment.save()
               if ids[1] is not None and ids[1] != '':
                   images = environment.image.all() #原镜像
                   print(f"primary_image_id:{experiment.primary_image_id}")
                   for image in images:
                       if int(experiment.primary_image_id) == int(image.id):
                           print(f"primary_image_id ::::::{image.id}")
                       else:
                           pi = self.get_object1(obj_id=int(image.id))
                           print(f"images{images}")
                           if pi:
                               print(f"imageid{pi.id}")
                               environment.image.remove(pi)
                   obj_id1 = int(ids[1])
                   ig = self.get_object1(obj_id=obj_id1)
                   if ig:
                       environment.image.add(ig)

        # if ids :
        #     if (len(ids)==1 or ids[]):
        #         environment.image.clear()
        #     for id in ids:
        #         if id:
        #           obj = self.get_object1(obj_id=id)
        #           environment.image.add(obj)
        # if id_list != None:
        #     environment.image.clear()
        #     for id in id_list:
        #         obj = self.get_object1(obj_id=id)
        #         if obj == None:
        #             continue
        #         environment.image.add(obj)
            serializer = EnvironmentCreateSerializer(environment)
        self.response_format["data"] = serializer.data
        
        return Response(self.response_format)
        

    def update(self, request, *args, **kwargs):
        try:
            super(EnvironmentUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "实验环境更新成功"
        except Exception as e:
            str(e)
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)


class ExperimentRemoveView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ExperimentRemoveView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            ret = Experiment.objects.get(id = obj_id) if self.request.user.user_type == 'A' else Experiment.objects.get(id = obj_id, teacher=self.request.user.teacher)
            return ret
        except Experiment.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Experiment.objects.get(id = id)
            """ try:
                DemoConfig.objects.get(id=id)
            except (DemoConfig.DoesNotExist, ValidationError):
                raise status.HTTP_400_BAD_REQUEST """
        return True

    def post(self, request, *args, **kwargs):
        id_list = request.data['experiments']
        instances = []
        try:
            status = trans.class_status[str(request.data['status'])]
        except: 
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "status参数错误"
            return Response(self.response_format)
        for id in id_list:
            obj = self.get_object(obj_id=id)
            if obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '实验ID:'+str(id)+'不存在\n'
                continue
            obj.status = status
            obj.save()
            self.message += '实验ID:'+str(id)+'状态修改成功\n'
            instances.append(obj)
        serializer = ExperimentRemoveSerializer(instances, many=True)
        self.response_format["message"] = self.message
        self.response_format["data"] = serializer.data
        return Response(self.response_format)
""" class QuestionListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    queryset = Question.objects.all()
    serializer_class = QuestionListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission]

    def get_queryset(self):
        queryset = Question.objects.all()
        question_id = self.request.query_params.get('question_id', None)
        question_name = self.request.query_params.get('question_name', None)
        question_type = self.request.query_params.get('question_type', None)
        knowledge_id = self.request.query_params.get('knowledge_id', None)
        banned = [None,'']
        if experiment_id not in banned:
            queryset = queryset.filter(id=experiment_id)
        if experiment_name not in banned:
            queryset = queryset.filter(experiment_name=experiment_name)
        if knowledge_id not in banned:
            queryset = queryset.filter(knowledge__id=knowledge_id)
        
        return queryset """

class EnvironmentRemoveView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(EnvironmentRemoveView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            ret = Environment.objects.get(id = obj_id, experiment__teacher=self.request.user.teacher)
            return ret
        except Environment.DoesNotExist:
            return None

    def validate_ids(self, id_list):
        for id in id_list:
            Experiment.objects.get(id = id)
            """ try:
                DemoConfig.objects.get(id=id)
            except (DemoConfig.DoesNotExist, ValidationError):
                raise status.HTTP_400_BAD_REQUEST """
        return True

    def post(self, request, *args, **kwargs):
        id_list = request.data['environments']
        for id in id_list:
            obj = self.get_object(obj_id=id)
            if obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '实验环境ID:'+str(id)+'不存在\n'
                continue
            if obj.instance_set.count() == 0:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '实验环境ID:'+str(id)+'已创建实例，无法删除\n'
                continue
            obj.delete()
            self.message += '实验环境ID:'+str(id)+'删除成功\n'
        self.response_format["message"] = self.message
        return Response(self.response_format)

class QuestionListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Question.objects.filter(status="N")
    serializer_class = QuestionListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission|pm.TeacherPermission]

    def get_queryset(self):
        queryset = Question.objects.filter(status="N").order_by('-create_time')
        question_id = self.request.query_params.get('id', None)
        question_type = self.request.query_params.get('question_type', None)
        knowledge_id = self.request.query_params.get('knowledge_id', None)
        question_name = self.request.query_params.get('question_name', None)
        banned = [None,'']
        if question_id not in banned:
            queryset = queryset.filter(id=question_id)
        if question_type not in banned:
            queryset = queryset.filter(question_type=question_type)
        if knowledge_id not in banned:
            queryset = queryset.filter(knowledge__id=knowledge_id)
        if question_name not in banned:
            queryset = queryset.filter(Q(choicedetail__describe__contains=question_name) | Q(blankdetail__describe__contains=question_name))

        # if self.request.user.user_type == 'T':
        #     queryset = queryset.filter(owner=self.request.user)
        
        return queryset

class BlankQuestionCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = BlankQuestionCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(BlankQuestionCreateViewSet, self).__init__(**kwargs)
    def get_object1(self, obj_id):
        try:
            return Knowledge.objects.get(id = obj_id)
        except Knowledge.DoesNotExist:
            return None
    def perform_create(self, serializer):
        with transaction.atomic():
            question_type = self.request.data['question_type'] if self.request.data['question_type'] in ['BL','SA'] else 'SA'
            judge_type = self.request.data['judge_type'] if self.request.data['judge_type'] in ['M','K','E'] else 'M'
            question_new = Question.addOne(question_type, self.request.user, judge_type=judge_type)

            knowledge_list = GetPostParaOrNone(self.request.data,"knowledges")
            if knowledge_list != None:
                for id in knowledge_list:
                    obj = self.get_object1(obj_id=id)
                    if obj == None:
                        continue
                    question_new.knowledge.add(obj)
            bd = BlankDetail.addOne(self.request.data['question_name'], question_new, str(self.request.data['question_answer']))
        
        serializer = BlankQuestionCreateSerializer(question_new)
        self.response_format["data"] = serializer.data
    def create(self, request, *args, **kwargs):
        try:
            super(BlankQuestionCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "简答题创建成功"
        except Exception as e:
            traceback.print_exc()
            logger.error(str(e))
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class ChoiceQuestionCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = ChoiceQuestionCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ChoiceQuestionCreateViewSet, self).__init__(**kwargs)
    def get_object1(self, obj_id):
        try:
            return Knowledge.objects.get(id = obj_id)
        except Knowledge.DoesNotExist:
            return None
    def perform_create(self, serializer):
        with transaction.atomic():
            question_type = self.request.data['question_type'] if self.request.data['question_type'] in ['MC','MA','TF'] else 'MC'
            question_new = Question.addOne(question_type, self.request.user)
            knowledge_list = GetPostParaOrNone(self.request.data,"knowledges")
            if knowledge_list != None:
                for id in knowledge_list:
                    obj = self.get_object1(obj_id=id)
                    if obj == None:
                        continue
                    question_new.knowledge.add(obj)
            cd = ChoiceDetail.addOne(self.request.data['question_name'], question_new)
            answer_list = GetPostParaOrNone(self.request.data, "answers")
            if answer_list != None:
                for answer in answer_list:
                    OptionDetail.addOne(answer['content'], answer['is_correct'], cd, self.request.user)
        
        serializer = ChoiceQuestionCreateSerializer(question_new)
        self.response_format["data"] = serializer.data
    def create(self, request, *args, **kwargs):
        try:
            super(ChoiceQuestionCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "选择题创建成功"
        except Exception as err:
            logger.error(err)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)

class ChoiceQuestionOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = ChoiceQuestionSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ChoiceQuestionOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Question.objects.filter(Q(id = self.kwargs['pk']), (Q(question_type='MA')|Q(question_type='MC')|Q(question_type='TF')))

    def retrieve(self, request, question_id=None):
        queryset = Question.objects.filter(Q(question_type='MA')|Q(question_type='MC')|Q(question_type='TF'))
        try:
            one = queryset.get(id = self.kwargs['question_id'])
            serializer = ChoiceQuestionSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Question.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '题目ID不存在'
        
        return Response(self.response_format)

class KnowledgeOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = KnowledgeDetailSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(KnowledgeOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Knowledge.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, knowledge_id=None):
        queryset = Knowledge.objects.all()
        try:
            one = queryset.get(id = self.kwargs['knowledge_id'])
            serializer = KnowledgeDetailSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Knowledge.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '知识点ID不存在'
        
        return Response(self.response_format)

class OptionDetailOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = OptionDetailSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(OptionDetailOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return OptionDetail.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, optiondetail_id=None):
        queryset = OptionDetail.objects.all()
        try:
            one = queryset.get(id = self.kwargs['optiondetail_id'])
            serializer = OptionDetailSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except OptionDetail.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '选项ID不存在'
        
        return Response(self.response_format)

class BlankQuestionOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = BlankQuestionSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(BlankQuestionOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Question.objects.filter(Q(id = self.kwargs['pk']), (Q(question_type='BL')|Q(question_type='SA')))

    def retrieve(self, request, question_id=None):
        queryset = Question.objects.filter(Q(question_type='BL')|Q(question_type='SA'))
        try:
            one = queryset.get(id = self.kwargs['question_id'])
            serializer = BlankQuestionSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Question.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '题目ID不存在'
        
        return Response(self.response_format)

class ChoiceQuestionUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = ChoiceQuestionUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ChoiceQuestionUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return Question.objects.filter(Q(id = self.kwargs['id']), Q(owner=self.request.user), (Q(question_type='MA')|Q(question_type='MC')|Q(question_type='TF')))

    def perform_update(self, serializer):
        with transaction.atomic():
            question = serializer.save()
            question_type = GetPostParaOrNone(self.request.data,"question_type")
            question_name = GetPostParaOrNone(self.request.data,"question_name")
            answer_list = GetPostParaOrNone(self.request.data,"answers")
            knowledge_list = GetPostParaOrNone(self.request.data,"knowledges")
            status = GetPostParaOrNone(self.request.data,"status")
            if status is not None and str(status) in trans.class_status.keys():
                question.status = trans.class_status[str(status)]
                question.save()
            
            if question_name is not None:
                cd = question.choicedetail
                cd.describe = question_name
                cd.save()
            
            if question_type is not None and str(question_type) in ['MA','MC','TF']:
                question.question_type = question_type
                question.save()

            OptionDetail.objects.filter(choice_detail=question.choicedetail).delete()

            if answer_list != None:
                for answer in answer_list:
                    OptionDetail.addOne(answer['content'], answer['is_correct'], question.choicedetail, self.request.user)

            if knowledge_list != None:
                question.knowledge.clear()
                for knowledge_id in knowledge_list:
                    try:
                        knowledge = Knowledge.objects.get(id=knowledge_id)
                        question.knowledge.add(knowledge)
                    except:
                        continue

    def update(self, request, *args, **kwargs):
        try:
            super(ChoiceQuestionUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "选择题更新成功"
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)

class OptionDetailCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = OptionDetailCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(OptionDetailCreateViewSet, self).__init__(**kwargs)
    
    def perform_create(self, serializer):
        optiondetail = OptionDetail()
        optiondetail.content = self.request.data['content']
        optiondetail.is_correct = self.request.data['is_correct']
        optiondetail.owner = self.request.user
        optiondetail.save()
        
        serializer = OptionDetailCreateSerializer(optiondetail)
        self.response_format["data"] = serializer.data
    def create(self, request, *args, **kwargs):
        try:
            super(OptionDetailCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "选择题选项创建成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class BlankQuestionUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = BlankQuestionUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(BlankQuestionUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        return Question.objects.filter(Q(id = self.kwargs['id']), Q(owner=self.request.user), (Q(question_type='BL')|Q(question_type='SA')))

    def perform_update(self, serializer):
        question = serializer.save()
        question_type = GetPostParaOrNone(self.request.data,"question_type")
        judge_type = GetPostParaOrNone(self.request.data,"judge_type")
        question_name = GetPostParaOrNone(self.request.data,"question_name")
        question_answer = GetPostParaOrNone(self.request.data,"question_answer")
        knowledge_list = GetPostParaOrNone(self.request.data,"knowledges")
        status = GetPostParaOrNone(self.request.data,"status")
        if status is not None and str(status) in trans.class_status.keys():
            question.status = trans.class_status[str(status)]
            question.save()
        
        if question_name is not None:
            cd = question.blankdetail
            cd.describe = question_name
            cd.save()
        
        if question_type is not None and str(question_type) in ['BL','SA']:
            question.question_type = question_type
            question.save()

        if judge_type is not None and str(judge_type) in ['M','K','E']:
            question.judge_type = judge_type
            question.save()

        if question_answer != None:
            bd = question.blankdetail
            bd.answer = question_answer
            bd.save()

        if knowledge_list != None:
            question.knowledge.clear()
            for knowledge_id in knowledge_list:
                try:
                    knowledge = Knowledge.objects.get(id=knowledge_id)
                    question.knowledge.add(knowledge)
                except:
                    continue

    def update(self, request, *args, **kwargs):
        try:
            super(BlankQuestionUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "简答题更新成功"
        except Http404 as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '数据不存在或无权操作该数据'
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class QuestionRemoveView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(QuestionRemoveView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            ret = Question.objects.get(id = obj_id, owner=self.request.user)
            return ret
        except Question.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        try:
            id_list = request.data['questions']
            status = request.data['status']
            for id in id_list:
                obj = self.get_object(obj_id=id)
                if obj == None:
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.message += '题目ID:'+str(id)+'不存在\n'
                    continue
                obj.status = trans.class_status[str(status)] if str(status) in trans.class_status.keys() else "C"
                obj.save()
                self.message += '题目ID:'+str(id)+'删除成功\n'
            self.response_format["message"] = self.message
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)

        return Response(self.response_format)
class ReportOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = ReportSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ReportOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Report.objects.filter(Q(id = self.kwargs['pk']), Q(experiment__teacher=self.request.user.teacher))

    def retrieve(self, request, report_id=None):
        queryset = Report.objects.filter(Q(experiment__teacher=self.request.user.teacher))
        try:
            one = queryset.get(id = self.kwargs['report_id'])
            serializer = ReportSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Report.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '实验报告ID不存在'
        
        return Response(self.response_format)


class ReportDownloadViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = ReportSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ReportDownloadViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Report.objects.filter(Q(id = self.kwargs['pk']), Q(experiment__teacher=self.request.user.teacher))

    def retrieve(self, request, report_id=None):
        queryset = Report.objects.filter(Q(experiment__teacher=self.request.user.teacher))
        try:
            one = queryset.get(id = self.kwargs['report_id'])
            # serializer = ReportSerializer(one, context={"request": request})
            # data = serializer.data
            #todo compress report file and experiment log
            report_name = 'report_{}_experiment_{}_stu_{}.zip'.format(one.title, one.experiment.experiment_name, one.student.user.real_name)
            zipf =  os.path.dirname(os.path.dirname(__file__)) + '/BatchImportFiles/' + report_name
            eventLogFile =  os.path.dirname(os.path.dirname(__file__)) + '/BatchImportFiles/log_{}_experiment_{}_stu_{}.csv'.format(one.id, one.experiment_id, one.student_id)
            with open(eventLogFile, 'w') as file:
                logs = readReportLogs(one.student.user, one.experiment_id)
                for l in logs:
                    d = WebEventSerializer(l).data
                    file.write(d['username'] + '\t,' + d['create_ts'] + '\t,' + d['detail'] + '\n')
            with ZipFile(zipf, 'w') as myzip:
                myzip.write(eventLogFile, os.path.basename(eventLogFile))
                for a in one.attach_set.all():
                    rf = os.path.dirname(__file__) + '/media/' + str(a.location)
                    if os.path.exists(rf):
                        myzip.write(rf, arcname=os.path.basename(rf))
            zip_file = open(zipf, 'rb')
            return FileResponse(zip_file, filename=report_name)

        except Report.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '实验报告ID不存在'
            return Response(self.response_format)

class ReportScoreUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = ReportScoreSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ReportScoreUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        ret = Report.objects.filter(Q(id = self.kwargs['id']), Q(experiment__teacher=self.request.user.teacher))
        return ret

    def perform_update(self, serializer):
        report = serializer.save()
        serializer = ReportScoreSerializer(report)
        self.response_format["data"] = serializer.data

        # 若大于60分，自动获取对应的知识点
        if report.score is not None and report.score> 60:
            knowledges = report.experiment.knowledge.all()
            for k in knowledges:
                student = report.student
                student.knowledge.add(k.id)
        
        return Response(self.response_format)
        

    def update(self, request, *args, **kwargs):
        try:
            super(ReportScoreUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "实验报告评分成功"
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)


class ExamManualCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = ExamCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(ExamManualCreateViewSet, self).__init__(**kwargs)

    def perform_create(self, serializer):
        # total 为题量
        assert int(self.request.data['MC']['score']) + int(self.request.data['MA']['score']) + int(self.request.data['TF']['score']) + int(self.request.data['BL']['score']) + int(self.request.data['SA']['score']) == 100
        assert int(self.request.data['MC']['total']) + int(self.request.data['MA']['total']) + int(self.request.data['TF']['total']) + int(self.request.data['BL']['total']) + int(self.request.data['SA']['total']) > 0
        assert int(self.request.data['MC']['score']) % int(self.request.data['MC']['total']) == 0
        assert int(self.request.data['MA']['score']) % int(self.request.data['MA']['total']) == 0
        assert int(self.request.data['TF']['score']) % int(self.request.data['TF']['total']) == 0
        assert int(self.request.data['BL']['score']) % int(self.request.data['BL']['total']) == 0
        assert int(self.request.data['SA']['score']) % int(self.request.data['SA']['total']) == 0
        course = Course.objects.get(id=self.request.data['course_id'], teacher=self.request.user.teacher)
        exam_new = serializer.save()
        exam_new.course = course
        exam_new.question_total = int(self.request.data['MC']['total']) + int(self.request.data['MA']['total']) + int(self.request.data['TF']['total']) + int(self.request.data['BL']['total']) + int(self.request.data['SA']['total'])
        exam_new.save()
        
        mc_single_score = int(self.request.data['MC']['score']) / int(self.request.data['MC']['total'])
        ma_single_score = int(self.request.data['MA']['score']) / int(self.request.data['MA']['total'])
        tf_single_score = int(self.request.data['TF']['score']) / int(self.request.data['TF']['total'])
        bl_single_score = int(self.request.data['BL']['score']) / int(self.request.data['BL']['total'])
        sa_single_score = int(self.request.data['SA']['score']) / int(self.request.data['SA']['total'])
        order = 0
        for i in range(int(self.request.data['MC']['total'])):
            order = order + 1
            eq = ExamQuestion()
            eq.exam = exam_new
            eq.question_type = 'MC'
            eq.value = mc_single_score
            eq.order = order
            eq.save()
        for i in range(int(self.request.data['MA']['total'])):
            order = order + 1
            eq = ExamQuestion()
            eq.exam = exam_new
            eq.question_type = 'MA'
            eq.value = ma_single_score
            eq.order = order
            eq.save()
        for i in range(int(self.request.data['TF']['total'])):
            order = order + 1
            eq = ExamQuestion()
            eq.exam = exam_new
            eq.question_type = 'TF'
            eq.value = tf_single_score
            eq.order = order
            eq.save()
        for i in range(int(self.request.data['BL']['total'])):
            order = order + 1
            eq = ExamQuestion()
            eq.exam = exam_new
            eq.question_type = 'BL'
            eq.value = bl_single_score
            eq.order = order
            eq.save()
        for i in range(int(self.request.data['SA']['total'])):
            order = order + 1
            eq = ExamQuestion()
            eq.exam = exam_new
            eq.question_type = 'SA'
            eq.value = sa_single_score
            eq.order = order
            eq.save()
        
        serializer = ExamCreateSerializer(exam_new)
        self.response_format["data"] = serializer.data
    def create(self, request, *args, **kwargs):
        try:
            super(ExamManualCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "手动组卷成功"
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)

class ExamUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = ExamUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(ExamUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        ret = Exam.objects.filter(id = self.kwargs['id'], course__teacher=self.request.user.teacher)
        return ret

    def get_object1(self, obj_id):
        try:
            return Knowledge.objects.get(id = obj_id)
        except Knowledge.DoesNotExist:
            return None

    def perform_update(self, serializer):
        exam = serializer.save()
        course_id = GetPostParaOrNone(self.request.data,"course_id")
        if course_id != None:
            course = Course.objects.get(id=course_id, teacher=self.request.user.teacher)
            exam.course = course
            exam.save()
        serializer = ExamUpdateSerializer(exam)
        self.response_format["data"] = serializer.data
        
        return Response(self.response_format)
        

    def update(self, request, *args, **kwargs):
        try:
            super(ExamUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "考试更新成功"
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)


class PaperOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = PaperSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(PaperOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Paper.objects.filter(Q(id = self.kwargs['pk']), Q(exam__course__teacher=self.request.user.teacher))

    def retrieve(self, request, paper_id=None):
        queryset = Paper.objects.filter(Q(exam__course__teacher=self.request.user.teacher))
        try:
            one = queryset.get(id = self.kwargs['paper_id'])
            serializer = PaperSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Paper.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '试卷ID不存在'
        
        return Response(self.response_format)

class PaperUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = PaperUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(PaperUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        ret = Paper.objects.filter(id = self.kwargs['id'], exam__course__teacher=self.request.user.teacher)
        return ret

    def update(self, request, *args, **kwargs):
        try:
            super(PaperUpdateViewSet, self).update(request, *args, **kwargs)
            self.response_format["message"] = "考试更新成功"
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "参数错误"
        return Response(self.response_format)

class PaperQuestionUpdateViewSet(mixins.UpdateModelMixin, viewsets.GenericViewSet):
    serializer_class = PaperQuestionUpdateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]
    lookup_field = "id"
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(PaperQuestionUpdateViewSet, self).__init__(**kwargs)
    def get_queryset(self):
        ret = PaperQuestion.objects.filter(id = self.kwargs['id'], paper__exam__course__teacher=self.request.user.teacher)
        return ret

    def update(self, request, *args, **kwargs):
        try:
            super(PaperQuestionUpdateViewSet, self).update(request, *args, **kwargs)
            # todo 修改题目分值
            self.response_format["message"] = "手动打分成功"
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class LogoutViewSet(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        print('init log out')
        self.response_format = CustomResponse().response
        self.message = ""
        super(LogoutViewSet, self).__init__(**kwargs)

    def handle_exception(self, exc):
        """
        Handle any exception that occurs, by returning an appropriate response,
        or re-raising the error.
        """
        print('exc: ', exc)
        if isinstance(exc, (exceptions.NotAuthenticated,
                            exceptions.AuthenticationFailed)):
            # WWW-Authenticate header for 401 responses, else coerce to 403
            auth_header = self.get_authenticate_header(self.request)
            print('auth_header: ', auth_header)

            if auth_header:
                exc.auth_header = auth_header
            else:
                exc.status_code = status.HTTP_403_FORBIDDEN

        exception_handler = self.get_exception_handler()

        context = self.get_exception_handler_context()
        response = exception_handler(exc, context)

        if response is None:
            self.raise_uncaught_exception(exc)

        response.exception = True
        return response

    def post(self, request, *args, **kwargs):
        try:
            print('post log out')
            auth_logout(self.request)
            response = Response(self.response_format)
            response.delete_cookie(key='USER_TYPE', domain=settings.SESSION_COOKIE_DOMAIN)
            response.delete_cookie('USER_NAME', domain=settings.SESSION_COOKIE_DOMAIN)
            response.delete_cookie('USER_EMAIL', domain=settings.SESSION_COOKIE_DOMAIN)
            response.delete_cookie('USER_REAL_NAME', domain=settings.SESSION_COOKIE_DOMAIN)
            response.delete_cookie('USER_PHONE', domain=settings.SESSION_COOKIE_DOMAIN)
            response.delete_cookie('vlab_session_id', domain=settings.SESSION_COOKIE_DOMAIN)
            response.delete_cookie(settings.SESSION_COOKIE_NAME, domain=settings.SESSION_COOKIE_DOMAIN)
            return response
        except Exception as e:
            print(str(e))
            traceback.print_exc()
    
class LoginViewSet(LoginView):
    """
    Display the login form and handle the login action.
    """
    template_name = 'registration/login.html'
    redirect_authenticated_user = True

    def form_valid(self, form):
        """Security check complete. Log the user in."""
        response = super().form_valid(form)
        response.charset = 'utf8'
        user = self.request.user
        expires = 86400 * 365
        print('ability.views.LoginViewSet', user, expires, settings.SESSION_COOKIE_DOMAIN)
        response.set_cookie(key='USER_TYPE', value=user.user_type, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        response.set_cookie('USER_NAME', user.username.encode("utf-8"), expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        response.set_cookie('USER_EMAIL', user.email, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        # todo UnicodeEncodeError: 'latin-1' codec can't encode characters 中文乱码
        response.set_cookie('USER_REAL_NAME', json.dumps(user.real_name), expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        response.set_cookie('USER_PHONE', user.phone, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        return response

    def get_success_url(self):
        user = self.request.user
        url = settings.LOGIN_REDIRECT_URL if user.user_type == 'A' or user.user_type == 'E'  else settings.TEA_LOGIN_REDIRECT_URL if user.user_type == 'T' else settings.STU_LOGIN_REDIRECT_URL
        return url

def CasLoginCallback(request):
    if request.method == 'GET':
        ticket = request.GET['ticket']
        try:
            user_id, user_name, id_type, college_name = cas.serviceValidate(ticket)
        except cas.CasError as e:
            return HttpResponseRedirect(settings.NOUSER_PAGE)
        user = UserProfile.objects.filter(username=user_id).first()
        if user is None:
            # return HttpResponseRedirect(settings.NOUSER_PAGE)
            user_type = 'S' if id_type == '1' else 'T'
            with transaction.atomic():
                user = UserProfile.addOne(user_id, user_name, user_type)
                if id_type == '1':
                    student = Student.addOne(user, studentID=user_id)
                else:
                    colllege_id = None
                    college = College.objects.filter(college_name=college_name).first()
                    if college is not None:
                        college_id = college.id
                    teacher = Teacher.addOne(user, college_id, 'C', teacherID=user_id)
        url = settings.LOGIN_REDIRECT_URL if user.user_type == 'A' or user.user_type == 'E'  else settings.TEA_LOGIN_REDIRECT_URL if user.user_type == 'T' else settings.STU_LOGIN_REDIRECT_URL
        response = HttpResponseRedirect(url)
        response.charset = 'utf8'
        expires = 86400 * 365
        response.set_cookie(key='USER_TYPE', value=user.user_type, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        response.set_cookie('USER_NAME', user.username.encode("utf-8"), expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        response.set_cookie('USER_EMAIL', user.email, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        # todo UnicodeEncodeError: 'latin-1' codec can't encode characters 中文乱码
        response.set_cookie('USER_REAL_NAME', json.dumps(user.real_name), expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        response.set_cookie('USER_PHONE', user.phone, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN)
        auth_login(request, user)
        return response

class ExamListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Exam.objects.all()
    serializer_class = ExamListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.TeacherPermission]

    def get_queryset(self):
        queryset = Exam.objects.filter(owner=self.request.user).order_by('-id')
        exam_name = self.request.query_params.get('exam_name', None)
        banned = [None,'']
        if exam_name not in banned:
            queryset = queryset.filter(exam__exam_name__icontains=exam_name)
        # if course_name not in banned:
        #     queryset = queryset.filter(exam__course__course_name__icontains=course_name)
        return queryset

class AchievementListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    serializer_class = KnowledgeSerializer
    model = serializer_class.Meta.model
    queryset = Knowledge.objects.all()
    
    def get_queryset(self):
        return Knowledge.objects.filter(student=self.request.user.student)

class StuCourseListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Course.objects.all()
    serializer_class = CourseListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def get_serializer_context(self):
        context = super(StuCourseListViewSet, self).get_serializer_context()
        context.update({"request": self.request})
        return context

    def get_queryset(self):
        all_course_id = []
        for i in StudentCourse.objects.filter(student=self.request.user.student, status='N').order_by('-id'):
            all_course_id.append(i.course.id)
        queryset = Course.objects.filter(id__in=all_course_id, status='N').order_by('-id')
        return queryset

class OpenCourseListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Course.objects.all()
    serializer_class = OpenCourseListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def get_queryset(self):
        queryset = Course.objects.filter(course_type='E', status='N').all().order_by('-create_time')
        course_id = self.request.query_params.get('course_id', None)
        course_name = self.request.query_params.get('course_name', None)
        teacher_name = self.request.query_params.get('teacher_name', None)
        banned = [None,'']
        if course_id not in banned:
            queryset = queryset.filter(id=course_id)
        if course_name not in banned:
            queryset = queryset.filter(course_name=course_name)
        if teacher_name not in banned:
            queryset = queryset.filter(teacher__user__real_name__icontains='teacher_name')
        
        return queryset

class StuCourseOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = StuCourseSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StuCourseOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Course.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, course_id=None):
        all_course_id = []
        for i in StudentCourse.objects.filter(student=self.request.user.student, status='N').order_by('-choose_time'):
            all_course_id.append(i.course.id)
        queryset = Course.objects.filter(id__in=all_course_id)
        try:
            one = queryset.get(id = self.kwargs['course_id'])
            serializer = StuCourseSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Course.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '课程不存在'
        
        return Response(self.response_format)

class StuChapterOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = StuChapterSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StuChapterOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Chapter.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, chapter_id=None):
        queryset = Chapter.objects.filter(course__student=self.request.user.student)
        try:
            one = queryset.get(id = self.kwargs['chapter_id'])
            serializer = StuChapterSerializer(one)
            self.response_format["data"] = serializer.data
        except Chapter.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '章节ID不存在'
        
        return Response(self.response_format)

class StuExperimentListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Experiment.objects.all()
    serializer_class = StuExperimentListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission | pm.AdminPermission]

    def get_serializer_context(self):
        context = super(StuExperimentListViewSet, self).get_serializer_context()
        context.update({"request": self.request})
        return context

    def get_queryset(self):
        queryset = Experiment.objects.filter(student=self.request.user.student, status='N')
        return queryset.order_by('-id')

class StuReportOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = StuReportSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StuReportOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Report.objects.filter(Q(id = self.kwargs['pk']), Q(student=self.request.user.student))

    def retrieve(self, request, report_id=None):
        queryset = Report.objects.filter(student=self.request.user.student)
        try:
            one = queryset.get(id = self.kwargs['report_id'])
            serializer = StuReportSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Report.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '实验报告ID不存在'
        
        return Response(self.response_format)

class StuExperimentOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = StuExperimentSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StuExperimentOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Experiment.objects.filter(id = self.kwargs['pk'])

    def retrieve(self, request, experiment_id=None):
        try:
            student = self.request.user.student
            print(self.kwargs['experiment_id'])
            if(len(StudentExperiment.objects.filter(student=student,experiment_id=self.kwargs['experiment_id'])) == 0):
                raise Exception('实验不存在')
            experiment = Experiment.objects.get(id=self.kwargs['experiment_id'])
            print(experiment)
            # experiment = queryset.get(id = self.kwargs['experiment_id'])
            if experiment is None:
                raise Exception('实验不存在')
            # todo experiment expired
            # if timeutil.comp(experiment.ending_time, datetime.now()) == -1:
            #     raise Exception('实验已过截止时间')
            serializer = StuExperimentSerializer(experiment, context={"student": request.user.student})

            data = serializer.data
            data['describe'] = data['describe'][:101]
            vnc_host = ''
            if data['instance'][0]['Status'] == 'RUNNING':
                # PublicIpAddresses = data['instance'][0]['PublicIpAddresses']
                vm_id = data['instance'][0]['instanceId']
                # PublicIpAddresses = '49.232.252.248'
                vncServe = VncServer.objects.filter(host=vm_id).order_by('-port').first()
                if vncServe is None:
                    one = VncServer.objects.order_by('-port').first()
                    if one is None:
                        vncServers = VncServer.objects.values('host', 'port')
                        for item in vncServers:
                            kill_process_by_port(item['port'])
                        VncServer.objects.filter(id__gt=0).delete()
                        pt = 6080
                    else:
                        pt = one.port

                    while True:
                        #检查端口占用
                        if port_occupancy_check(pt) == False:
                            break
                        pt += 1

                    if pt >= 7080:
                       pt = 6080
                    vncServe = VncServer()
                    vncServe.host = vm_id
                    # vncServe.host = PublicIpAddresses
                    vncServe.port = pt
                    vncServe.save()
                    run_onvnc(vncServe.port, data['instance'][0]['port'])
                    vnc_host = "http://"+settings.VNC_IP+":" + str(vncServe.port) + '/vnc_lite.html'
                    # vnc_host = "https://axtx.email:" + str(vncServe.port) + '/vnc_lite.html'
                else:
                    if port_occupancy_check(vncServe.port) == False:
                        run_onvnc(vncServe.port,data['instance'][0]['port'])
                    vnc_host = "http://"+settings.VNC_IP+":" + str(vncServe.port) + '/vnc_lite.html'
                    # vnc_host = "https://axtx.email:" + str(vncServe.port) + '/vnc_lite.html'

            data['vnc_url'] = vnc_host
            data['instance'][0]['doraemon'] = 'https://dsdO$rr'+'Adr5@_d6dhnr'+'ee.cboot.net'
            # data['instance'][0]['doraemon'] = 'https://dsdO$rr'+'Ad{r5@_d6dhnr'+'ee.cboot.net'
            ins = Instance.objects.filter(instanceId=data['instance'][0]['InsId']).first()
            create_ts = ""
            if ins is not None:
                create_ts = ins.create_ts.strftime("%Y-%m-%d %H:%M:%S")
            data['instance'][0]['create_st'] = create_ts
            self.response_format["data"] = data
        except Experiment.DoesNotExist:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '实验ID不存在'
        except TencentCloudSDKException as e:
            self.response_format["error_code"] = ErrorCode.tcent_error.value
            self.response_format["message"] = str(e.message)
        except Exception as e:
            traceback.print_exc()
            vncServers = VncServer.objects.values('host', 'port')
            for item in vncServers:
                kill_process_by_port(item['port'])
            VncServer.objects.filter(id__gt=0).delete()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        
        return Response(self.response_format)


class TestSpeed(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(TestSpeed, self).__init__(**kwargs)

    def retrieve(self, request, experiment_id=None):
        data = test_internet_speed()
        return Response(data)

class MemoryUsage(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(MemoryUsage, self).__init__(**kwargs)

    def retrieve(self, request, experiment_id=None):
        try:
            ip = request.GET.get('ip')
            logger.error(ip)
            port = request.GET.get('port')
            logger.error(port)
            url = str('http://' + ip + ":" + port + "/df-h")
            logger.error(url)
            response = requests.get(url)
            data = response.json()
            logger.error(data)
        except:
            data = {
                "code": 200,
                "data": "连接失败，请稍后重试"
            }
        return JsonResponse(data)

class FileDownload(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(FileDownload, self).__init__(**kwargs)

    # 调用FastAPI的文件下载接口
    def retrieve(self, request, experiment_id=None):
        ip = request.GET.get('ip')
        fileName = request.GET.get('fileName')
        url = str('http://'+ip+":7079"+"/file-download?fileName="+fileName)

        response = requests.get(url, stream=True)

        # 将FastAPI的文件下载接口的返回值转换为Django的FileResponse对象
        django_response = FileResponse(
            response.raw,
            content_type=response.headers["Content-Type"]
        )
        django_response["Content-Disposition"] = response.headers["Content-Disposition"]
        django_response["Content-Length"] = response.headers["Content-Length"]
        return django_response

        # return Response(response.content)
        # response = requests.get(url)
        # logger.error(type(response))
        # # data = response.json()
        # logger.error("=======================")
        # logger.error(response)
        # # logger.error(data)
        # logger.error("=======================")

        # 将文件响应对象转换为普通响应对象
        # return FileResponse(response)
        # return FileResponse(
        #   data['filePath'],
        #   **{"filename": f"{data['filename']}"}
        # )
        # return FileResponse(
        #     response.request.path_url,# 获取文件路径
        #     **{"filename": f"{response.headers.get('Content-Disposition')}"}  # 获取文件名
        # )

class FileUpload(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    serializer_class = FileUploadSerializer
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(FileUpload, self).__init__(**kwargs)

    def get_serializer_class(self):
        return FileUploadSerializer

    from rest_framework import serializers

    class FileUploadSerializer(serializers.Serializer):
        file = serializers.FileField()

    def create(self, request, ip):
        serializer = FileUploadSerializer(data=request.data)

        if serializer.is_valid():
            file = serializer.validated_data['file']

            url = str('http://{}:7079/file-upload'.format(ip))
            files = {'file': (file.name, file)}

            # 发送POST请求给FastAPI
            response = requests.post(url, files=files)

            # 返回响应
            return HttpResponse(response)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    # def create(self, request, ip):
    #     file = request.FILES.get('file')
    #     if file:
    #         url = str('http://'+ip+":7079/file-upload")
    #         files = {'file': (file.name,file)}
    #         #发送POST请求给FastAPI
    #         response = requests.post(url,files=files)
    #         return HttpResponse(response)

class FileTransferStationFiles(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        # self.response_format = CustomResponse().response
        super(FileTransferStationFiles, self).__init__(**kwargs)

    def retrieve(self, request, experiment_id=None):
        try:
            ip = request.GET.get('ip')
            logger.error(ip)
            url = str('http://' + ip + ":7079/filetransfer-station-files")
            logger.error(url)
            response = requests.get(url)
            data = response.json()
            logger.error(data)
            data = {
                "code": 200,
                "data": {
                    'file_transfer_station_files': data['data']['file_transfer_station_files']
                }
            }
        except:
            data = {
                "code": 200,
                "data": "连接失败，请稍后重试"
            }
        return JsonResponse(data)
        # return Response(response)

class StuExamListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = Exam.objects.all()
    serializer_class = StuExamListSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def get_serializer_context(self):
        context = super(StuExamListViewSet, self).get_serializer_context()
        context.update({"request": self.request})
        return context

    def get_queryset(self):
        queryset = Exam.objects.filter(course__student = self.request.user.student)
        course_id = self.request.query_params.get('course_id', None)
        banned = [None,'']
        if course_id not in banned:
            queryset = queryset.filter(course_id=course_id)
        return queryset.order_by('-id')

class StuExamOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = StuExamSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StuExamOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        # return Exam.objects.filter(Q(id = self.kwargs['pk']), Q(course__student=self.request.user.student))
        return Exam.objects.filter(Q(id = self.kwargs['pk']))

    def retrieve(self, request, exam_id=None):
        # queryset = Exam.objects.filter(Q(course__coursestudent__student=self.request.user.student))
        queryset = Exam.objects
        try:
            one = queryset.get(id = self.kwargs['exam_id'], course__student=request.user.student)
            serializer = ExamSerializer(one, context={"request": request})
            # one = queryset.get(id = self.kwargs['exam_id'])
            # serializer = StuExamSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Exam.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '考试ID不存在'
        
        return Response(self.response_format)

class StuPaperOneViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    serializer_class = PaperSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StuPaperOneViewSet, self).__init__(**kwargs)
    
    def get_queryset(self):
        return Paper.objects.filter(Q(exam_id = self.kwargs['exam_id']), Q(student=self.request.user.student))

    def retrieve(self, request, exam_id=None):
        queryset = Paper.objects.filter(Q(student=self.request.user.student))
        try:
            one = queryset.get(exam_id = self.kwargs['exam_id'])
            serializer = PaperSerializer(one, context={"request": request})
            self.response_format["data"] = serializer.data
        except Paper.DoesNotExist:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = '未参与该场考试'
        
        return Response(self.response_format)

class StuPaperCreateView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(StuPaperCreateView, self).__init__(**kwargs)
    
    def get_paper(self, exam):
        try: 
            return Paper.objects.get(student=self.request.user.student, exam=exam)
        except:
            return None

    def post(self, request, *args, **kwargs):
        try:
            exam_id = request.data['exam_id']
            exam = Exam.objects.get(id=exam_id, course__student=self.request.user.student)
            paper = self.get_paper(exam)
            if paper is not None:
                serializer = StuPaperCreateSerializer(paper)
                self.response_format["data"] = serializer.data
                self.response_format["message"] = '考试开始'
                return Response(self.response_format)

            if StudentCourse.objects.get(student=self.request.user.student, course=exam.course).status == 'C':
                raise Exception('该试卷不在考试时间')
            time_diff = datetime.now() - exam.start_time.replace(tzinfo=None)
            time_delta = time_diff.total_seconds() // 60

            logger.error('utcnow:{}, sta: {}'.format(datetime.now(), exam.start_time.replace(tzinfo=None)))

            if time_delta < 0:
                raise Exception('考试尚未开始')

            if time_delta > exam.duration:
                raise Exception('考试已结束')

            paper = Paper()
            paper.student = self.request.user.student
            paper.exam = exam
            paper.save()
            serializer = StuPaperCreateSerializer(paper)
            self.response_format["data"] = serializer.data
            self.response_format["message"] = '考试开始'
            return Response(self.response_format)
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)

class StuChoiceAnswerView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(StuChoiceAnswerView, self).__init__(**kwargs)

    def get_paper_question(self, paper_id, question_id):
        try:
            return PaperQuestion.objects.get(paper_id=paper_id, question_id=question_id)
        except:
            return None 

    def get_exam_question(self, exam_id, question_id):
        try:
            return ExamQuestion.objects.get(exam_id=exam_id, question_id=question_id)
        except:
            return None

    def post(self, request, *args, **kwargs):
        try:
            choice_answers = request.data['choice_answers']
            choices = ['MC', 'MA', 'TF']
            paper_id = request.data['paper_id']
            exam_id = request.data['exam_id']
            question_id = request.data['question_id']
            with transaction.atomic():
                exam_ques = self.get_exam_question(exam_id, question_id)
                if exam_ques is None:
                    raise Exception('题目不存在')

                if exam_ques.question.question_type not in choices:
                    raise Exception('题目类型错误')

                pq = self.get_paper_question(paper_id, exam_ques.id)
                paper = Paper.objects.get(id=paper_id)
                if paper is None:
                    raise Exception('尚未报名考试')

                if paper.status == 'C':
                    raise Exception('考试已结束')

                if paper.student != self.request.user.student:
                    raise Exception('请重试进入考场')

                if timeutil.expired(paper.expire_time): 
                    raise Exception('考试已经结束')

                if pq is None:
                    pq = PaperQuestion()
                    pq.paper = paper
                    pq.question = exam_ques
                    pq.save()

                if exam_ques.question.question_type == 'MC':
                    assert len(choice_answers)==1

                if pq is not None:
                    pq.choice_answer.clear()
                    for choice_answer in choice_answers:
                        ca = OptionDetail.objects.get(id=choice_answer)
                        print(choice_answer, ca, ca.choice_detail, ca.choice_detail.question)
                        print(pq, pq.question, pq.question.question)
                        if ca.choice_detail.question != pq.question.question:
                            raise  Exception('选项有误')
                        pq.choice_answer.add(ca)
                    pq.save()
            self.response_format["message"] = '选择题答案提交成功'
            return Response(self.response_format)
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)

class StuBlankAnswerView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(StuBlankAnswerView, self).__init__(**kwargs)

    def get_paper_question(self, paper_id, question_id):
        try:
            return PaperQuestion.objects.get(paper_id=paper_id, question_id=question_id)
        except:
            return None 

    def get_exam_question(self, exam_id, question_id):
        try:
            return ExamQuestion.objects.get(exam_id=exam_id, question_id=question_id)
        except:
            return None

    def post(self, request, *args, **kwargs):
        try:
            # paper_question = request.data['paper_question']
            blank_answer = request.data['blank_answer']
            paper_id = request.data['paper_id']
            exam_id = request.data['exam_id']
            question_id = request.data['question_id']
            exam_ques = self.get_exam_question(exam_id, question_id)
            if exam_ques is None:
                raise Exception('题目不存在')

            paper = Paper.objects.get(id=paper_id)
            if paper is None:
                raise Exception('尚未报名考试')

            if paper.student != self.request.user.student:
                raise Exception('请重试进入考场')
            if paper.status == 'C':
                raise Exception('考试已结束')

            if paper.student != self.request.user.student:
                raise Exception('请重试进入考场')

            if timeutil.expired(paper.expire_time): 
                raise Exception('考试已经结束')


            with transaction.atomic():
                pq = self.get_paper_question(paper_id, exam_ques.id)

                if pq is None:
                    exam_ques = self.get_exam_question(exam_id, exam_ques.id)
                    pq = PaperQuestion()
                    pq.paper = paper
                    pq.question = exam_ques
                    pq.save()

                choices = ['BL','SA']
                if exam_ques.question.question_type != pq.question.question.question_type:
                    raise Exception('题目类型错误')
                if exam_ques.question.question_type not in choices:
                    raise Exception('题目类型错误')

                pq.blank_answer = blank_answer
                pq.save()
            self.response_format["message"] = '填空题答案提交成功'
            return Response(self.response_format)
        except Exception as e:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)

class StuPaperSubmitView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(StuPaperSubmitView, self).__init__(**kwargs)

    def get_standard_answers(self, pq):
        optiondetails = pq.question.question.choicedetail.optiondetail_set.all()
        stan = []
        for od in optiondetails:
            if od.is_correct == True:
                stan.append(od.id)
        return stan

    def get_student_answers(self, pq):
        optiondetails = pq.choice_answer.all()
        stan = []
        for od in optiondetails:
            stan.append(od.id)
        return stan

    def get_blank_standard_answers_split(self, pq):
        stan_temp = pq.question.question.blankdetail.answer
        stan = stan_temp.replace("；",";").split(";")
        return stan

    def get_blank_student_answers(self, pq):
        stan = pq.blank_answer
        return stan

    def post(self, request, *args, **kwargs):
        try:
            with transaction.atomic():
                paper_id = request.data['paper_id']
                paper = Paper.objects.get(id=paper_id)
                assert paper.student == self.request.user.student
                # time_diff = datetime.now() - paper.exam.start_time.replace(tzinfo=None)
                # time_delta = time_diff.total_seconds() // 60
                # assert time_delta > 0 and time_delta < paper.exam.duration
                # assert paper.status == 'N'

                if paper.exam.start_time:
                    time_diff = datetime.now() - paper.exam.start_time.replace(tzinfo=None)
                    time_delta = time_diff.total_seconds() // 60
                    if time_delta < 0 or time_delta > paper.exam.duration: raise Exception('不在考试时间')

                if timeutil.expired(paper.expire_time): 
                    raise Exception('考试已经结束')

                if paper.status == 'C':
                    raise Exception('考试已结束或已提交过答卷')

                paper.status = 'C'
                paper.save()
                choices = ['MC','MA','TF']
                blanks = ['BL','SA']
                pqs = PaperQuestion.objects.filter(paper=paper, question__question__question_type__in=choices)
                for pq in pqs: 
                    if self.get_standard_answers(pq) == self.get_student_answers(pq):
                        pq.is_correct = True
                        pq.originscore = pq.question.value
                        pq.correctscore = pq.question.value
                        knowledges = pq.question.question.knowledge.all()
                        for k in knowledges:
                            student = paper.student
                            student.knowledge.add(k.id)
                    else:
                        pq.originscore = 0
                        pq.correctscore = 0

                    pq.save()

                pqs = PaperQuestion.objects.filter(paper=paper, question__question__question_type__in=blanks)
                for pq in pqs: 
                    if pq.question.question.judge_type == 'E':
                        if pq.question.question.blankdetail.answer == self.get_blank_student_answers(pq):
                            pq.is_correct = True
                            pq.originscore = pq.question.value
                            pq.correctscore = pq.question.value
                            knowledges = pq.question.question.knowledge.all()
                            for k in knowledges:
                                student = paper.student
                                student.knowledge.add(k.id)
                        else:
                            pq.originscore = 0
                            pq.correctscore = 0
                    elif pq.question.question.judge_type == 'K':
                        ans = self.get_blank_standard_answers_split(pq)
                        stu_ans = self.get_blank_student_answers(pq)
                        total = len(ans)
                        stu_total = 0
                        for an in ans:
                            if stu_ans.count(an) > 0:
                                stu_total = stu_total + 1
                        score = pq.question.value * stu_total / total
                        if total == stu_total:
                            pq.is_correct = True
                            knowledges = pq.question.question.knowledge.all()
                            for k in knowledges:
                                student = paper.student
                                student.knowledge.add(k.id)
                        pq.originscore = score
                        pq.correctscore = score
                    else:
                        pq.originscore = 0
                        pq.correctscore = 0

                    pq.save()
                    
                paper_score = 0
                for pq in PaperQuestion.objects.filter(paper=paper):
                    paper_score = paper_score + pq.correctscore
                paper.score = paper_score
                paper.save()
                    
            self.response_format["message"] = '交卷成功'
            return Response(self.response_format)
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)
class StuReportCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = StuReportCreateSerializer
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        super(StuReportCreateViewSet, self).__init__(**kwargs)
    def get_attach(self, attach_id):
        try:
            # return Attach.objects.get(Q(id = attach_id), (Q(owner__user_type='A')|Q(owner__id=self.request.user.id)))
            return Attach.objects.get(Q(id = attach_id))
        except Attach.DoesNotExist:
            return None
    
    def get_richtext(self, obj_id):
        try:
            # return Attach.objects.get(Q(id = attach_id), (Q(owner__user_type='A')|Q(owner__id=self.request.user.id)))
            return RichTextAttach.objects.get(Q(id = obj_id))
        except Attach.DoesNotExist:
            return None
    
    def perform_create(self, serializer):
        report  = Report()
        report.title = self.request.data['title']
        report.content = self.request.data['content']
        report.experiment_id = self.request.data['experiment_id']
        report.student = self.request.user.student
        report.submit_time = datetime.now()
        report.save()
        attaches = self.request.data['attaches']
        for attach in attaches:
            rt = self.get_richtext(attach['id'])
            attach_obj = Attach()
            attach_obj.report = report
            attach_obj.file_type = 'D'
            attach_obj.location = rt.location
            attach_obj.file_name = rt.location
            attach_obj.save()

        imgs = self.request.data['imgs']
        for attach in imgs:
            rt = self.get_richtext(attach['id'])
            attach_obj = Attach()
            attach_obj.report = report
            attach_obj.file_type = 'I'
            attach_obj.location = rt.location
            attach_obj.file_name = rt.location
            attach_obj.save()
        
        videos = self.request.data['videos']

        for attach in videos:
            rt = self.get_richtext(attach['id'])
            attach_obj = Attach()
            attach_obj.report = report
            attach_obj.file_type = 'V'
            attach_obj.location = rt.location
            attach_obj.file_name = rt.location
            attach_obj.save()

        serializer = StuReportCreateSerializer(report)
        self.response_format["data"] = serializer.data
    def create(self, request, *args, **kwargs):
        try:
            super(StuReportCreateViewSet, self).create(request, *args, **kwargs)
            self.response_format["message"] = "实验报告提交成功"
        except Exception as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
        return Response(self.response_format)

class SsoGetTicketViewSet(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.TeacherPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(SsoGetTicketViewSet, self).__init__(**kwargs)
    
    def get(self, request, *args, **kwargs):
        ticket = sso.encrypt(self.request.user.username)
        self.response_format["data"] = ticket
        return Response(self.response_format)


class SsoGetUserInfoViewSet(APIView):

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(SsoGetUserInfoViewSet, self).__init__(**kwargs)
    
    def get(self, request, *args, **kwargs):
        username = sso.decrypt(self.request.GET['ticket'])
        if username is None:
            self.response_format['error_code'] = -1
            return Response(self.response_format)
        user = UserProfile.objects.filter(username=username).first()
        self.response_format["data"] =  {
            'username': user.username, 
            'user_type': user.user_type, 
            'email': user.email, 
            'real_name': user.real_name}
        print(self.response_format)
        return Response(self.response_format)

# 用户选择公开课
class StudentChoiceCourseView(APIView):

    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(StudentChoiceCourseView, self).__init__(**kwargs)
    
    def get_object(self, obj_id):
        try:
            return Student.objects.get(user__id = obj_id)
        except Student.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        course_id = request.data['course_id']
        action = request.data['action']
        choice_code = GetPostParaOrNone(request.data, 'choice_code')
        user = request.user
        try:
            assert action in ['add', 'remove']
        except Exception as e: 
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "action参数错误"
            return Response(self.response_format)
        try:
            course = Course.objects.get(id = course_id)
        except Course.DoesNotExist:
            self.response_format["message"] = "课程不存在"
            return Response(self.response_format)

        try:
            if course.course_type != 'E':
                raise Exception('非公开课不可选择')
            if course.choice_code != '' and course.choice_code != choice_code:
                raise Exception('选课码不正确')
            if course.status != 'N':
                raise Exception('该课程已下架')
            student = self.request.user.student
            if action == 'add':
                if course.capacity > 0 and course.student_set.count() >= course.capacity:
                    raise Exception('选课人数已满')
                if course in student.course.all():
                    raise Exception('您已选该课，请勿重新选课')
                student.course.add(course_id)
                self.message = '选课成功'
            else:
                if course not in student.course.all():
                    raise Exception('未选课程，无法取消选课')
                student.course.remove(course_id)
                self.message = '退课成功'
            self.response_format["message"] = self.message
            return Response(self.response_format)
        except Exception as e:
            logger.error(e)
            self.response_format["error_code"] = ErrorCode.comon_error.value
            self.response_format['message'] = str(e)
            return Response(self.response_format)

# class StudentInstanceActionView(APIView):
#
#     permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission|pm.AdminPermission]
#     def __init__(self, **kwargs):
#         self.response_format = CustomResponse().response
#         self.message = ""
#         super(StudentInstanceActionView, self).__init__(**kwargs)
#
#     def initial(self, request, *args, **kwargs):
#         try:
#             super().initial(request, *args, **kwargs)
#         except Exception as e:
#             traceback.print_exc()
#             print(e)
#             self.response_format["error_code"] = ErrorCode.parameter_error.value
#             self.response_format["message"] = "登录过期，请重新登录"
#             return Response(self.response_format)
#
#
#     def post(self, request, *args, **kwargs):
#         action = request.data['action']
#         imageId = GetPostParaOrNone(request.data, 'imageId')
#         insId = GetPostParaOrNone(request.data, 'insId')
#         envId = GetPostParaOrNone(request.data, 'envId')
#         user = request.user
#         environment = Environment.objects.filter(id=envId).first()
#         experiment = environment.experiment
#         images = environment.image.all()
#         if experiment.experiment_type == "double" and len(images) == 1:
#            images = [images[0],images[0]]
#         pii = None
#         cii = None
#         for ig in images:
#             print(f"实验相关镜像：{ig}")
#             if int(ig.id) == int(experiment.primary_image_id):
#                 pii = ig
#             else:
#                 cii = ig
#         # print(f"cii_imageid:{cii.id}")
#         if environment.experiment.experiment_type == "double" and len(images) == 2:
#             try:
#                 environment = Environment.objects.filter(id=envId).first()
#                 if environment is None:
#                     raise Exception('实验不存在')
#                 if action not in ['create', 'start', 'shutdown', 'recovery']:
#                     raise Exception('参数错误')
#                 if action == 'create':
#                     image = Image.objects.filter(imageId=imageId).first()
#                     if image is None :
#                         raise Exception('镜像不存在')
#                     ci = CloudImage()
#                     if Instance.objects.filter(environment=environment, student=user.student,image=pii, status='N').exists() and Instance.objects.filter(environment=environment, student=user.student,image=cii, status='N').exists():
#                         raise Exception('主机镜像和靶机镜像已创建，请刷新重试')
#                     logger.error('go issue image : {} '.format(image))
#                     # instanceid = ci.issue(image)
#                     # logger.error('instance id: {} '.format(instanceid))
#                     instance = Instance()
#                     instance_c = Instance()
#                     instance.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
#                     instance_c.name = user.real_name + "的" + environment.experiment.experiment_name + "靶机实例"
#                     # instance.instanceId = instanceid
#                     instance.environment = environment
#                     instance_c.environment = environment
#                     instance.student = user.student
#                     instance_c.student = user.student
#                     instance.create_ts = datetime.now()
#                     instance_c.create_ts = datetime.now()
#                     instance.image = pii
#                     instance_c.image = cii
#                     instance.experied_ts = instance.create_ts + timedelta(0, experiment.duration * 60)
#                     instance_c.experied_ts = instance.create_ts + timedelta(0, experiment.duration * 60)
#                     instanceOne = Instance.objects.filter(environment=environment, image=pii, status='N',
#                                                           student__isnull=True).first()
#                     instance_cii = Instance.objects.filter(environment=environment, image=cii, status='N',
#                                                           student__isnull=True).first()
#                     instanceid = None
#                     if instanceOne is None :
#                         logger.error("主机实例不存在，需要单独创建-_-!!!")
#                         print(f"instancePid：{instance.image.imageId}")
#                         instanceid = ci.issue(instance.image)
#                         logger.error('实例不存在，需要单独创建,instance id: {} '.format(instanceid))
#                         instance.instanceId = instanceid
#                         # instanceid = ci.issue(image)
#                         instance.save()
#                     else:
#                         logger.error("实例存在，以为您分配实例-_-!!!")
#                         logger.error('实例存在，以为您分配实例,instance id: {} '.format(instanceOne.instanceId))
#                         instanceOne.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
#                         instanceOne.student = user.student
#                         instanceOne.create_ts = datetime.now()
#                         instanceOne.experied_ts = datetime.now() + timedelta(0, experiment.duration * 60)
#                         print("============")
#                         print(f"主机镜像：{instanceOne}")
#                         print("============")
#                         instanceOne.save()
#                         instanceid = instanceOne.instanceId
#                     instanceid_cii = None
#                     if instance_cii is None :
#                         logger.error("主机实例不存在，需要单独创建-_-!!!")
#                         print(f"instancePid：{instance_c.image.imageId}")
#                         instanceid_cii = ci.issue(instance_c.image)
#                         logger.error('实例不存在，需要单独创建,instance id: {} '.format(instanceid_cii))
#                         instance_c.instanceId = instanceid_cii
#                         # instanceid = ci.issue(image)
#                         instance_c.save()
#                     else:
#                         logger.error("实例存在，以为您分配实例-_-!!!")
#                         logger.error('实例存在，以为您分配实例,instance id: {} '.format(instance_cii.instanceId))
#                         instance_cii.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
#                         instance_cii.student = user.student
#                         instance_cii.create_ts = datetime.now()
#                         instance_cii.experied_ts = datetime.now() + timedelta(0, experiment.duration * 60)
#                         print("============")
#                         print(f"靶机镜像：{instance_cii}")
#                         print("============")
#                         instance_cii.save()
#                         instanceid_cii = instanceOne.instanceId
#                     # instance.save()
#                     self.response_format["message"] = '实例创建成功'
#                     if (not StudentExperiment.objects.filter(experiment=experiment, student=user.student).count() > 0):
#                         StudentExperiment(student=user.student, experiment=experiment).save()
#                     study_record_data_send(request, experiment.id, instanceid+":"+instanceid_cii, 'create')
#                     virtual_data_send(request, experiment.id, 'create')
#                 if action == 'start':
#                     if not Instance.objects.filter(image=pii, student = user.student , environment = environment,status = "N").exists():
#                         raise Exception('主机实例不存在')
#                     if not Instance.objects.filter(image=cii, student= user.student , environment = environment,status = "N").exists():
#                         raise Exception('靶机实例不存在')
#                     ci = CloudInstance()
#                     pii_id = Instance.objects.get(image=pii, student=user.student, environment=environment,status = "N")
#                     cii_id = Instance.objects.get(image=cii, student=user.student, environment=environment,status = "N")
#                     ci.start([pii_id.instanceId,cii_id.instanceId])
#                     # instance = CloudInstance()
#                     # pii_ins = instance.DescribeInstance(pii_id)
#                     # cii_ins = instance.DescribeInstance(cii_id)
#                     # if ins.InstanceState != 'RUNNING':
#                     #    logger.error("ins.InstanceState的状态为".format(ins.InstanceState))
#                     #    ci = CloudInstance()
#                     #    ci.start([insId])
#                     self.response_format["message"] = '实例开机成功'
#                     if (StudentExperiment.objects.filter(experiment=experiment, student=user.student).count() > 0):
#                         StudentExperiment(student=user.student, experiment=experiment).save()
#                     study_record_data_send(request, experiment.id, pii_id.instanceId+":"+cii_id.instanceId, 'start')
#                     virtual_data_send(request, experiment.id, 'start')
#                 if action == 'shutdown':
#                     if not Instance.objects.filter(image=pii, student=user.student, environment=environment,status = "N").exists():
#                         raise Exception('主机实例不存在')
#                     if not Instance.objects.filter(image=cii, student=user.student, environment=environment,status = "N").exists():
#                         raise Exception('靶机实例不存在')
#                     pii_id = Instance.objects.get(image=pii, student=user.student, environment=environment,status = "N")
#                     cii_id = Instance.objects.get(image=cii, student=user.student, environment=environment,status = "N")
#                     ci = CloudInstance()
#                     ci.shutdown([pii_id.instanceId,cii_id.instanceId])
#                     self.response_format["message"] = '实例关机中'
#                     study_record_data_send(request, experiment.id, pii_id.instanceId+cii_id.instanceId, 'shutdown')
#                     virtual_data_send(request, experiment.id, 'shutdown')
#                     # 回收主机端口
#                     oneInstance = Instance.objects.filter(instanceId=pii_id.instanceId).first()
#                     vncServers = VncServer.objects.filter(host=oneInstance.ip_address).values('host', 'port')
#                     for item in vncServers:
#                         kill_process_by_port(item['port'])
#                     VncServer.objects.filter(host=oneInstance.ip_address).delete()
#
#                     # 回收靶机端口
#                     oneInstance_c = Instance.objects.filter(instanceId=cii_id.instanceId).first()
#                     vncServers = VncServer.objects.filter(host=oneInstance_c.ip_address).values('host', 'port')
#                     for item in vncServers:
#                         kill_process_by_port(item['port'])
#                     VncServer.objects.filter(host=oneInstance_c.ip_address).delete()
#                 if action == 'recovery':
#                     if not Instance.objects.filter(image=pii, student=user.student, environment=environment,status = "N").exists():
#                         raise Exception('主机实例不存在')
#                     if not Instance.objects.filter(image=cii, student=user.student, environment=environment,status = "N").exists():
#                         raise Exception('靶机实例不存在')
#                     pii_id = Instance.objects.get(image=pii, student=user.student, environment=environment,status = "N")
#                     cii_id = Instance.objects.get(image=cii, student=user.student, environment=environment,status = "N")
#                     virtual_data_send(request, experiment.id, 'delete')
#                     study_record_data_send(request, experiment.id, pii_id.instanceId+":"+cii_id.instanceId, 'delete')
#                     ci = CloudInstance()
#                     ci.recovery([pii_id.instanceId,cii_id.instanceId])
#                     self.response_format["message"] = '实例销毁中'
#                     # 回收端口
#                     # 回收主机端口
#                     oneInstance = Instance.objects.filter(instanceId=pii_id.instanceId).first()
#                     vncServers = VncServer.objects.filter(host=oneInstance.ip_address).values('host', 'port')
#                     for item in vncServers:
#                         kill_process_by_port(item['port'])
#                     VncServer.objects.filter(host=oneInstance.ip_address).delete()
#
#                     # 回收靶机端口
#                     oneInstance_c = Instance.objects.filter(instanceId=cii_id.instanceId).first()
#                     vncServers = VncServer.objects.filter(host=oneInstance_c.ip_address).values('host', 'port')
#                     for item in vncServers:
#                         kill_process_by_port(item['port'])
#                     VncServer.objects.filter(host=oneInstance_c.ip_address).delete()
#                     # 完成学练，添加记录到report表中
#                     # 如果不存在，则保存记录到report表中
#                     # 存在的话，则更新开始结束时间
#                     report = Report.objects.filter(student=user.student, experiment=experiment).first()
#                     if (report is None):
#                         report = Report()
#                         report.experiment = experiment
#                         report.student = user.student
#                         report.start_time = oneInstance.create_ts
#                         report.submit_time = datetime.now()
#                         report.save()
#                     else:
#                         report.start_time = oneInstance.create_ts
#                         report.submit_time = datetime.now()
#                         report.save()
#                 return Response(self.response_format)
#             except TencentCloudSDKException as e:
#                 logger.error(e)
#                 if str(e).__contains__("Request-sent") or str(e).__contains__("Idle"):
#                     self.response_format["error_code"] = ErrorCode.parameter_error.value
#                     self.response_format["message"] = "网络超时，请稍后重试！！！"
#                     return Response(self.response_format)
#                 if e.code == "InvalidInstanceId.NotFound":
#                     Instance.objects.filter(instanceId=insId).update(status='C')
#                     logger.error(e.code)
#                 self.response_format["error_code"] = ErrorCode.parameter_error.value
#                 self.response_format["message"] = str(e.message)
#                 return Response(self.response_format)
#                 # InvalidInstanceId.NotFound
#             except Exception as e:
#                 logger.error(e)
#                 traceback.print_exc()
#                 if str(e).__contains__("course"):
#                     print(e)
#                     return Response(self.response_format)
#                 self.response_format["error_code"] = ErrorCode.parameter_error.value
#                 self.response_format["message"] = str(e)
#                 return Response(self.response_format)
#         else:
#             try:
#                 environment = Environment.objects.filter(id=envId).first()
#                 if environment is None:
#                     raise Exception('实验不存在')
#                 experiment = environment.experiment
#                 if action not in ['create', 'start', 'shutdown', 'recovery']:
#                     raise Exception('参数错误')
#                 if action == 'create':
#                     image = Image.objects.filter(imageId=imageId).first()
#                     if image is None:
#                         raise Exception('镜像不存在')
#                     ci = CloudImage()
#                     if Instance.objects.filter(environment=environment, student=user.student, status='N').exists():
#                         raise Exception('实例已创建，请刷新重试')
#                     logger.error('go issue image : {} '.format(image))
#                     # instanceid = ci.issue(image)
#                     # logger.error('instance id: {} '.format(instanceid))
#                     instance = Instance()
#                     instance.name = user.real_name+"的" + environment.experiment.experiment_name+"主机实例"
#                     # instance.instanceId = instanceid
#                     instance.environment = environment
#                     instance.student = user.student
#                     instance.create_ts = datetime.now()
#                     instance.image = image
#                     instance.experied_ts = instance.create_ts  + timedelta(0, experiment.duration * 60)
#                     instanceOne = Instance.objects.filter(environment=environment, image=image,status='N',student__isnull=True).first()
#                     instanceid = None
#                     if instanceOne is None:
#                         logger.error("实例不存在，需要单独创建-_-!!!")
#                         instanceid = ci.issue(image)
#                         logger.error('实例不存在，需要单独创建,instance id: {} '.format(instanceid))
#                         instance.instanceId = instanceid
#                         # instanceid = ci.issue(image)
#                         instance.save()
#                     else:
#                         logger.error("实例存在，以为您分配实例-_-!!!")
#                         logger.error('实例存在，以为您分配实例,instance id: {} '.format(instanceOne.instanceId))
#                         instanceOne.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
#                         instanceOne.student = user.student
#                         instanceOne.create_ts = datetime.now()
#                         instanceOne.experied_ts = datetime.now() + timedelta(0, experiment.duration * 60)
#                         print("============")
#                         print(instanceOne)
#                         print("============")
#                         instanceOne.save()
#                         instanceid=instanceOne.instanceId
#                     # instance.save()
#                     self.response_format["message"] = '实例创建成功'
#                     print(instanceid)
#                     if (not StudentExperiment.objects.filter(experiment = experiment,student = user.student).count()>0):
#                         StudentExperiment(student=user.student,experiment=experiment).save()
#                     study_record_data_send(request, experiment.id, instanceid, 'create')
#                     virtual_data_send(request, experiment.id, 'create')
#                 if action == 'start':
#                     if not Instance.objects.filter(instanceId=insId).exists():
#                         raise Exception('实例不存在')
#                     ci = CloudInstance()
#                     ci.start([insId])
#                     instance = CloudInstance()
#                     ins = instance.DescribeInstance(insId)
#                     # if ins.InstanceState != 'RUNNING':
#                     #    logger.error("ins.InstanceState的状态为".format(ins.InstanceState))
#                     #    ci = CloudInstance()
#                     #    ci.start([insId])
#                     self.response_format["message"] =  '实例开机成功'
#                     if (StudentExperiment.objects.filter(experiment=experiment, student=user.student).count()>0):
#                         StudentExperiment(student=user.student, experiment=experiment).save()
#                     study_record_data_send(request, experiment.id, insId, 'start')
#                     virtual_data_send(request, experiment.id, 'start')
#                 if action == 'shutdown':
#                     if not Instance.objects.filter(instanceId=insId).exists():
#                         raise Exception('实例不存在')
#                     ci = CloudInstance()
#                     ci.shutdown([insId])
#                     self.response_format["message"] =  '实例关机中'
#                     study_record_data_send(request, experiment.id, insId, 'shutdown')
#                     virtual_data_send(request, experiment.id, 'shutdown')
#                     # 回收端口
#                     oneInstance = Instance.objects.filter(instanceId=insId).first()
#                     vncServers = VncServer.objects.filter(host=oneInstance.ip_address).values('host', 'port')
#                     for item in vncServers:
#                         kill_process_by_port(item['port'])
#                     VncServer.objects.filter(host=oneInstance.ip_address).delete()
#
#                 if action == 'recovery':
#                     if not Instance.objects.filter(instanceId=insId).exists():
#                         raise Exception('实例不存在')
#                     virtual_data_send(request, experiment.id, 'delete')
#                     study_record_data_send(request, experiment.id, insId, 'delete')
#                     ci = CloudInstance()
#                     ci.recovery([insId])
#                     self.response_format["message"] =  '实例销毁中'
#                     # 回收端口
#                     oneInstance = Instance.objects.filter(instanceId=insId).first()
#                     vncServers = VncServer.objects.filter(host=oneInstance.ip_address).values('host', 'port')
#                     for item in vncServers:
#                         kill_process_by_port(item['port'])
#                     VncServer.objects.filter(host=oneInstance.ip_address).delete()
#                     # 完成学练，添加记录到report表中
#                     # 如果不存在，则保存记录到report表中
#                     # 存在的话，则更新开始结束时间
#                     report = Report.objects.filter(student=user.student,experiment=experiment).first()
#                     if(report is None):
#                         report = Report()
#                         report.experiment = experiment
#                         report.student=user.student
#                         report.start_time=oneInstance.create_ts
#                         report.submit_time=datetime.now()
#                         report.save()
#                     else:
#                         report.start_time = oneInstance.create_ts
#                         report.submit_time = datetime.now()
#                         report.save()
#                 return Response(self.response_format)
#             except TencentCloudSDKException as e:
#                 logger.error(e)
#                 if str(e).__contains__("Request-sent") or str(e).__contains__("Idle") :
#                     self.response_format["error_code"] = ErrorCode.parameter_error.value
#                     self.response_format["message"] = "网络超时，请稍后重试！！！"
#                     return Response(self.response_format)
#                 if e.code == "InvalidInstanceId.NotFound":
#                     Instance.objects.filter(instanceId=insId).update(status='C')
#                     logger.error(e.code)
#                 self.response_format["error_code"] = ErrorCode.parameter_error.value
#                 self.response_format["message"] = str(e.message)
#                 return Response(self.response_format)
#                 #InvalidInstanceId.NotFound
#             except Exception as e:
#                 logger.error(e)
#                 traceback.print_exc()
#                 if str(e).__contains__("course"):
#                     print(e)
#                     return Response(self.response_format)
#                 self.response_format["error_code"] = ErrorCode.parameter_error.value
#                 self.response_format["message"] = str(e)
#                 return Response(self.response_format)


class StudentInstanceActionView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.StudentPermission | pm.AdminPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(StudentInstanceActionView, self).__init__(**kwargs)

    def initial(self, request, *args, **kwargs):
        try:
            super().initial(request, *args, **kwargs)
        except Exception as e:
            traceback.print_exc()
            print(e)
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = "登录过期，请重新登录"
            return Response(self.response_format)

    def post(self, request, *args, **kwargs):
        action = request.data['action']
        #镜像id
        imageId = GetPostParaOrNone(request.data, 'imageId')
        #实例id
        insId = GetPostParaOrNone(request.data, 'insId')
        #环境id
        envId = GetPostParaOrNone(request.data, 'envId')

        user = request.user

        environment = Environment.objects.filter(id=envId).first()
        #实验
        experiment = environment.experiment
        #环境的镜像
        images = environment.image.all()
        if experiment.experiment_type == "double" and len(images) == 1:
            images = [images[0], images[0]]
        pii = None
        cii = None
        for ig in images:
            print(f"实验相关镜像：{ig}")
            if int(ig.id) == int(experiment.primary_image_id):
                pii = ig
            else:
                cii = ig
        if environment.experiment.experiment_type == "double" and len(images) == 2:
            try:
                environment = Environment.objects.filter(id=envId).first()
                if environment is None:
                    raise Exception('实验不存在')
                if action not in ['create', 'start', 'shutdown', 'recovery']:
                    raise Exception('参数错误')
                if action == 'create':
                    image = Image.objects.filter(imageId=imageId).first()
                    if image is None:
                        raise Exception('镜像不存在')
                    # ci = CloudImage()
                    if Instance.objects.filter(environment=environment, student=user.student, image=pii,
                                               status='N').exists() and Instance.objects.filter(environment=environment,
                                                                                                student=user.student,
                                                                                                image=cii,
                                                                                                status='N').exists():
                        raise Exception('主机镜像和靶机镜像已创建，请刷新重试')
                    logger.error('go issue image : {} '.format(image))
                    # instanceid = ci.issue(image)
                    # logger.error('instance id: {} '.format(instanceid))
                    instance = Instance()
                    instance_c = Instance()
                    instance.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
                    instance_c.name = user.real_name + "的" + environment.experiment.experiment_name + "靶机实例"
                    # instance.instanceId = instanceid
                    instance.environment = environment
                    instance_c.environment = environment
                    instance.student = user.student
                    instance_c.student = user.student
                    instance.create_ts = datetime.now()
                    instance_c.create_ts = datetime.now()
                    instance.image = pii
                    instance_c.image = cii
                    instance.experied_ts = instance.create_ts + timedelta(0, experiment.duration * 60)
                    instance_c.experied_ts = instance.create_ts + timedelta(0, experiment.duration * 60)
                    instanceOne = Instance.objects.filter(environment=environment, image=pii, status='N',
                                                          student__isnull=True).first()
                    instance_cii = Instance.objects.filter(environment=environment, image=cii, status='N',
                                                           student__isnull=True).first()
                    instanceid = None
                    if instanceOne is None:
                        logger.error("主机实例不存在，需要单独创建-_-!!!")
                        logger.info(f"instancePid：{instance.image.imageId}")
                        # instanceid = ci.issue(instance.image)
                        instance_resp = proxmox.create_vm(instance.image.imageId)
                        instanceid = instance_resp['vmid']
                        logger.error('实例不存在，需要单独创建,instance id: {} '.format(instanceid))
                        instance.instanceId = instance_resp['instance_id']
                        logger.info(instance_resp['port'])
                        instance.port=instance_resp['port']
                        # instanceid = ci.issue(image)
                        instance.save()
                    else:
                        logger.error('实例存在，以为您分配实例,instance id: {} '.format(instanceOne.instanceId))
                        instanceOne.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
                        instanceOne.student = user.student
                        instanceOne.create_ts = datetime.now()
                        instanceOne.experied_ts = datetime.now() + timedelta(0, experiment.duration * 60)
                        logger.info("============")
                        logger.info(f"主机镜像：{instanceOne}")
                        logger.info("============")
                        instanceOne.save()
                        instanceid = instanceOne.instanceId
                    instanceid_cii = None
                    if instance_cii is None:
                        logger.error("主机实例不存在，需要单独创建-_-!!!")
                        print(f"instancePid：{instance_c.image.imageId}")
                        # instanceid_cii = ci.issue(instance_c.image)
                        instance_resp= proxmox.create_vm(instance_c.imageId)
                        instanceid_cii = instance_resp['vmid']
                        logger.error('实例不存在，需要单独创建,instance id: {} '.format(instanceid_cii))
                        instance_c.instanceId = instanceid_cii
                        instance_c.port = instance_resp['port']
                        # instanceid = ci.issue(image)
                        instance_c.save()
                    else:
                        logger.error('实例存在，以为您分配实例,instance id: {} '.format(instance_cii.instanceId))
                        instance_cii.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
                        instance_cii.student = user.student
                        instance_cii.create_ts = datetime.now()
                        instance_cii.experied_ts = datetime.now() + timedelta(0, experiment.duration * 60)
                        print("============")
                        print(f"靶机镜像：{instance_cii}")
                        print("============")
                        instance_cii.save()
                        instanceid_cii = instanceOne.instanceId
                    # instance.save()
                    self.response_format["message"] = '实例创建成功'
                    if (not StudentExperiment.objects.filter(experiment=experiment, student=user.student).count() > 0):
                        StudentExperiment(student=user.student, experiment=experiment).save()
                    study_record_data_send(request, experiment.id, instanceid + ":" + instanceid_cii, 'create')
                    virtual_data_send(request, experiment.id, 'create')
                if action == 'start':
                    if not Instance.objects.filter(image=pii, student=user.student, environment=environment,
                                                   status="N").exists():
                        raise Exception('主机实例不存在')
                    if not Instance.objects.filter(image=cii, student=user.student, environment=environment,
                                                   status="N").exists():
                        raise Exception('靶机实例不存在')
                    # ci = CloudInstance()
                    pii_id = Instance.objects.get(image=pii, student=user.student, environment=environment, status="N")
                    cii_id = Instance.objects.get(image=cii, student=user.student, environment=environment, status="N")
                    proxmox.start_vm(pii_id.instanceId)
                    proxmox.start_vm(cii_id.isntanceId)
                    # ci.start([pii_id.instanceId, cii_id.instanceId])
                    # instance = CloudInstance()
                    # pii_ins = instance.DescribeInstance(pii_id)
                    # cii_ins = instance.DescribeInstance(cii_id)
                    # if ins.InstanceState != 'RUNNING':
                    #    logger.error("ins.InstanceState的状态为".format(ins.InstanceState))
                    #    ci = CloudInstance()
                    #    ci.start([insId])
                    self.response_format["message"] = '实例开机成功'
                    if (StudentExperiment.objects.filter(experiment=experiment, student=user.student).count() > 0):
                        StudentExperiment(student=user.student, experiment=experiment).save()
                    study_record_data_send(request, experiment.id, pii_id.instanceId + ":" + cii_id.instanceId, 'start')
                    virtual_data_send(request, experiment.id, 'start')
                if action == 'shutdown':
                    if not Instance.objects.filter(image=pii, student=user.student, environment=environment,
                                                   status="N").exists():
                        raise Exception('主机实例不存在')
                    if not Instance.objects.filter(image=cii, student=user.student, environment=environment,
                                                   status="N").exists():
                        raise Exception('靶机实例不存在')
                    pii_id = Instance.objects.get(image=pii, student=user.student, environment=environment, status="N")
                    cii_id = Instance.objects.get(image=cii, student=user.student, environment=environment, status="N")
                    # ci = CloudInstance()
                    # ci.shutdown([pii_id.instanceId, cii_id.instanceId])
                    proxmox.showdown_vm(pii_id.instanceId)
                    proxmox.showdown_vm(cii_id.instanceId)
                    self.response_format["message"] = '实例关机中'
                    study_record_data_send(request, experiment.id, pii_id.instanceId + cii_id.instanceId, 'shutdown')
                    virtual_data_send(request, experiment.id, 'shutdown')
                    # 回收主机端口
                    oneInstance = Instance.objects.filter(instanceId=pii_id.instanceId).first()
                    vncServers = VncServer.objects.filter(host=oneInstance.ip_address).values('host', 'port')
                    for item in vncServers:
                        kill_process_by_port(item['port'])
                    VncServer.objects.filter(host=oneInstance.ip_address).delete()

                    # 回收靶机端口
                    oneInstance_c = Instance.objects.filter(instanceId=cii_id.instanceId).first()
                    vncServers = VncServer.objects.filter(host=oneInstance_c.ip_address).values('host', 'port')
                    for item in vncServers:
                        kill_process_by_port(item['port'])
                    VncServer.objects.filter(host=oneInstance_c.ip_address).delete()
                if action == 'recovery':
                    if not Instance.objects.filter(image=pii, student=user.student, environment=environment,
                                                   status="N").exists():
                        raise Exception('主机实例不存在')
                    if not Instance.objects.filter(image=cii, student=user.student, environment=environment,
                                                   status="N").exists():
                        raise Exception('靶机实例不存在')
                    pii_id = Instance.objects.get(image=pii, student=user.student, environment=environment, status="N")
                    cii_id = Instance.objects.get(image=cii, student=user.student, environment=environment, status="N")
                    virtual_data_send(request, experiment.id, 'delete')
                    study_record_data_send(request, experiment.id, pii_id.instanceId + ":" + cii_id.instanceId,
                                           'delete')
                    proxmox.delete_vm(pii_id.instanceId)
                    proxmox.delete_vm(cii_id.instanceId)
                    # ci = CloudInstance()
                    # ci.recovery([pii_id.instanceId, cii_id.instanceId])
                    self.response_format["message"] = '实例销毁中'
                    # 回收端口
                    # 回收主机端口
                    oneInstance = Instance.objects.filter(instanceId=pii_id.instanceId).first()
                    vncServers = VncServer.objects.filter(host=oneInstance.instanceId).values('host', 'port')
                    # vncServers = VncServer.objects.filter(host=oneInstance.ip_address).values('host', 'port')
                    for item in vncServers:
                        kill_process_by_port(item['port'])
                    VncServer.objects.filter(host=oneInstance.ip_address).delete()

                    # 回收靶机端口
                    oneInstance_c = Instance.objects.filter(instanceId=cii_id.instanceId).first()
                    vncServers = VncServer.objects.filter(host=oneInstance_c.instanceId).values('host', 'port')
                    # vncServers = VncServer.objects.filter(host=oneInstance_c.ip_address).values('host', 'port')
                    for item in vncServers:
                        kill_process_by_port(item['port'])
                    VncServer.objects.filter(host=oneInstance_c.ip_address).delete()
                    # 完成学练，添加记录到report表中
                    # 如果不存在，则保存记录到report表中
                    # 存在的话，则更新开始结束时间
                    report = Report.objects.filter(student=user.student, experiment=experiment).first()
                    if (report is None):
                        report = Report()
                        report.experiment = experiment
                        report.student = user.student
                        report.start_time = oneInstance.create_ts
                        report.submit_time = datetime.now()
                        report.save()
                    else:
                        report.start_time = oneInstance.create_ts
                        report.submit_time = datetime.now()
                        report.save()
                return Response(self.response_format)
            except TencentCloudSDKException as e:
                logger.error(e)
                if str(e).__contains__("Request-sent") or str(e).__contains__("Idle"):
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.response_format["message"] = "网络超时，请稍后重试！！！"
                    return Response(self.response_format)
                if e.code == "InvalidInstanceId.NotFound":
                    Instance.objects.filter(instanceId=insId).update(status='C')
                    logger.error(e.code)
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.response_format["message"] = str(e.message)
                return Response(self.response_format)
                # InvalidInstanceId.NotFound
            except Exception as e:
                logger.error(e)
                traceback.print_exc()
                if str(e).__contains__("course"):
                    print(e)
                    return Response(self.response_format)
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.response_format["message"] = str(e)
                return Response(self.response_format)
        else:
            try:
                environment = Environment.objects.filter(id=envId).first()
                if environment is None:
                    raise Exception('实验不存在')
                experiment = environment.experiment
                if action not in ['create', 'start', 'shutdown', 'recovery']:
                    raise Exception('参数错误')
                if action == 'create':
                    image = Image.objects.filter(imageId=imageId).first()
                    if image is None:
                        raise Exception('镜像不存在')
                    # ci = CloudImage()
                    if Instance.objects.filter(environment=environment, student=user.student, status='N').exists():
                        raise Exception('实例已创建，请刷新重试')
                    logger.error('go issue image : {} '.format(image))
                    # instanceid = ci.issue(image)
                    # logger.error('instance id: {} '.format(instanceid))
                    instance = Instance()
                    instance.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
                    # instance.instanceId = instanceid
                    instance.environment = environment
                    instance.student = user.student
                    instance.create_ts = datetime.now()
                    instance.image = image
                    instance.experied_ts = instance.create_ts + timedelta(0, experiment.duration * 60)
                    instanceOne = Instance.objects.filter(environment=environment, image=image, status='N',
                                                          student__isnull=True).first()
                    instanceid = None
                    if instanceOne is None:
                        logger.error("实例不存在，需要单独创建-_-!!!")
                        instance_resp=proxmox.create_vm(102)
                        instanceid = instance_resp['vmid']
                        # instanceid = ci.issue(image)
                        logger.error('实例不存在，需要单独创建,instance id: {} '.format(instanceid))
                        instance.instanceId = instanceid
                        instance.port = instance_resp['port']
                        # instanceid = ci.issue(image)
                        instance.save()
                    else:
                        logger.error('实例存在，以为您分配实例,instance id: {} '.format(instanceOne.instanceId))
                        instanceOne.name = user.real_name + "的" + environment.experiment.experiment_name + "主机实例"
                        instanceOne.student = user.student
                        instanceOne.create_ts = datetime.now()
                        instanceOne.experied_ts = datetime.now() + timedelta(0, experiment.duration * 60)
                        print("============")
                        print(instanceOne)
                        print("============")
                        instanceOne.save()
                        instanceid = instanceOne.instanceId
                    # instance.save()
                    self.response_format["message"] = '实例创建成功'
                    logger.info(instanceid)
                    if (not StudentExperiment.objects.filter(experiment=experiment, student=user.student).count() > 0):
                        StudentExperiment(student=user.student, experiment=experiment).save()
                    study_record_data_send(request, experiment.id, instanceid, 'create')
                    virtual_data_send(request, experiment.id, 'create')
                if action == 'start':
                    if not Instance.objects.filter(instanceId=insId).exists():
                        raise Exception('实例不存在')
                    # ci = CloudInstance()
                    # ci.start([insId])
                    proxmox.start_vm(insId)
                    # instance = CloudInstance()
                    # ins = instance.DescribeInstance(insId)
                    # if ins.InstanceState != 'RUNNING':
                    #    logger.error("ins.InstanceState的状态为".format(ins.InstanceState))
                    #    ci = CloudInstance()
                    #    ci.start([insId])
                    self.response_format["message"] = '实例开机成功'
                    if (StudentExperiment.objects.filter(experiment=experiment, student=user.student).count() > 0):
                        StudentExperiment(student=user.student, experiment=experiment).save()
                    study_record_data_send(request, experiment.id, insId, 'start')
                    virtual_data_send(request, experiment.id, 'start')
                if action == 'shutdown':
                    if not Instance.objects.filter(instanceId=insId).exists():
                        raise Exception('实例不存在')
                    # ci = CloudInstance()
                    # ci.shutdown([insId])
                    proxmox.shutdown_wm(insId)
                    self.response_format["message"] = '实例关机中'
                    study_record_data_send(request, experiment.id, insId, 'shutdown')
                    virtual_data_send(request, experiment.id, 'shutdown')
                    # 回收端口
                    oneInstance = Instance.objects.filter(instanceId=insId).first()
                    vncServers = VncServer.objects.filter(host=oneInstance.ip_address).values('host', 'port')
                    for item in vncServers:
                        kill_process_by_port(item['port'])
                    VncServer.objects.filter(host=oneInstance.ip_address).delete()

                if action == 'recovery':
                    if not Instance.objects.filter(instanceId=insId).exists():
                        raise Exception('实例不存在')
                    virtual_data_send(request, experiment.id, 'delete')
                    study_record_data_send(request, experiment.id, insId, 'delete')
                    # ci = CloudInstance()
                    # ci.recovery([insId])
                    proxmox.delete_vm(insId)
                    self.response_format["message"] = '实例销毁中'
                    # 回收端口
                    oneInstance = Instance.objects.filter(instanceId=insId).first()
                    vncServers = VncServer.objects.filter(host=oneInstance.instanceId).values('host', 'port')
                    # vncServers = VncServer.objects.filter(host=oneInstance.ip_address).values('host', 'port')
                    for item in vncServers:
                        kill_process_by_port(item['port'])
                    VncServer.objects.filter(host=oneInstance.ip_address).delete()
                    # 完成学练，添加记录到report表中
                    # 如果不存在，则保存记录到report表中
                    # 存在的话，则更新开始结束时间
                    report = Report.objects.filter(student=user.student, experiment=experiment).first()
                    if (report is None):
                        report = Report()
                        report.experiment = experiment
                        report.student = user.student
                        report.start_time = oneInstance.create_ts
                        report.submit_time = datetime.now()
                        report.save()
                    else:
                        report.start_time = oneInstance.create_ts
                        report.submit_time = datetime.now()
                        report.save()
                return Response(self.response_format)
            except TencentCloudSDKException as e:
                logger.error(e)
                if str(e).__contains__("Request-sent") or str(e).__contains__("Idle"):
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    self.response_format["message"] = "网络超时，请稍后重试！！！"
                    return Response(self.response_format)
                if e.code == "InvalidInstanceId.NotFound":
                    Instance.objects.filter(instanceId=insId).update(status='C')
                    logger.error(e.code)
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.response_format["message"] = str(e.message)
                return Response(self.response_format)
                # InvalidInstanceId.NotFound
            except Exception as e:
                logger.error(e)
                traceback.print_exc()
                if str(e).__contains__("course"):
                    print(e)
                    return Response(self.response_format)
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.response_format["message"] = str(e)
                return Response(self.response_format)

class InstanceCreateView(APIView):
    permission_classes = [pm.CustomIsAuthenticated, pm.AdminPermission | pm.TeacherPermission]

    def __init__(self, **kwargs):
        self.response_format = CustomResponse().response
        self.message = ""
        super(InstanceCreateView, self).__init__(**kwargs)

    def get_env_object(self, obj_id):
        try:
            ret = Environment.objects.get(id=obj_id)
            serializer = EnvironmentSerializer(ret, context={"request": request})
            logger.error('get_env_object 获取实验环境: Environment: %s ', serializer.data)
            return ret
        except Environment.DoesNotExist:
            return None
    def get_image_object(self, env):
        try:
            ret = env.image.all().first()
            serializer = ImageSerializer(ret, context={"request": request})
            logger.error('get_env_object 获取实验镜像: %s ', serializer.data)
            return ret
        except Image.DoesNotExist:
            return None

    def post(self, request, *args, **kwargs):
        try:
            env_id = request.data['env_id']
            inst_count = request.data['inst_count']
            logger.error('InstanceCreateView 批量创建实例参数: env_id: %s ，env_id： %s ',env_id,inst_count)
        except Exception as e:
            traceback.print_exc()
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"] = str(e)
            return Response(self.response_format)

        env_obj = self.get_env_object(obj_id=env_id)
        logger.error('InstanceCreateView 获取环境: env: %s ', env_obj)
        InstanceIdSet = []
        live_ins_count = Instance.objects.filter(environment=env_obj).exclude(status='C').count()
        if env_obj == None:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.message += '实验环境ID:' + str(env_id) + '不存在\n'
        elif inst_count+live_ins_count > 50:
            self.response_format["error_code"] = ErrorCode.parameter_error.value
            self.response_format["message"]="当前已存在"+str(live_ins_count)+"个存活实例，创建的实例最多为50个\n"
        else:
            image_obj = self.get_image_object(env=env_obj)
            if image_obj == None:
                self.response_format["error_code"] = ErrorCode.parameter_error.value
                self.message += '实验环境所关联的镜像' + str(env_obj.image) + '已失效\n'
            else:
                try:
                    ci = CloudImage()
                    success_count = 0
                    InstanceIdSet = ci.issueBatch(image_obj,inst_count);
                    logger.error('instance ids: {} '.format(InstanceIdSet))
                    for instanceid in InstanceIdSet:
                        instance = Instance()
                        instance.name = "批量创建[" +  env_obj.experiment.experiment_name + "]_主机实例_" +str(instanceid)
                        instance.instanceId = instanceid
                        instance.environment = env_obj
                        #instance.student
                        instance.create_ts = datetime.now()
                        instance.image = image_obj
                        instance.experied_ts = instance.create_ts + timedelta(0, env_obj.experiment.duration * 60)
                        instance.save()
                        success_count =success_count + 1
                        study_record_data_send(request, env_obj.experiment.id, instanceid, 'create')
                        # virtual_data_send(request, env_obj.experiment.id, 'create_batch')
                    self.response_format["message"] = '实例批量创建成功[' + str(success_count) + ']条'
                    self.response_format["data"] = InstanceIdSet
                except Exception as e:
                    traceback.print_exc()
                    self.response_format["error_code"] = ErrorCode.parameter_error.value
                    if str(e).__contains__("Request-sent"):
                        self.response_format["message"] = "正在批量创建实例"
                    else:
                        self.response_format["message"] = str(e)
                    return Response(self.response_format)
        return Response(self.response_format)